/** * Mindmap-Seite JavaScript * Spezifische Funktionen für die Mindmap-Seite */ // Füge das Modul zum globalen MindMap-Objekt hinzu if (!window.MindMap) { window.MindMap = {}; } // Registriere den Initialisierer im MindMap-Objekt if (window.MindMap) { window.MindMap.pageInitializers = window.MindMap.pageInitializers || {}; window.MindMap.pageInitializers.mindmap = initMindmapPage; } // Initialisiere die Mindmap-Seite nur, wenn alle Abhängigkeiten vorhanden sind if (window.MindMap && typeof MindMapVisualization !== 'undefined') { if (document.body && document.body.dataset && document.body.dataset.page === 'mindmap') { window.MindMap.pageInitializers = window.MindMap.pageInitializers || {}; window.MindMap.pageInitializers.mindmap = initMindmapPage; initMindmapPage(); } } document.addEventListener('DOMContentLoaded', function() { // Prüfe, ob wir auf der Mindmap-Seite sind und initialisiere if (document.body && document.body.dataset && document.body.dataset.page === 'mindmap') { initMindmapPage(); } }); /** * Initialisiert die Mindmap-Seite */ function initMindmapPage() { console.log('Mindmap-Seite Initialisierung startet...'); console.log('D3 Bibliothek verfügbar:', typeof d3 !== 'undefined'); console.log('MindMapVisualization verfügbar:', typeof MindMapVisualization !== 'undefined'); const mindmapContainer = document.getElementById('mindmap-container'); const thoughtsContainer = document.getElementById('thoughts-container'); if (!mindmapContainer) { console.error('Mindmap-Container nicht gefunden!'); return; } console.log('Mindmap-Container gefunden:', mindmapContainer); // Prüfe, ob D3.js geladen ist if (typeof d3 === 'undefined') { console.error('D3.js ist nicht geladen!'); mindmapContainer.innerHTML = `

D3.js konnte nicht geladen werden. Bitte laden Sie die Seite neu.

`; return; } // Prüfe, ob MindMapVisualization definiert ist if (typeof MindMapVisualization === 'undefined') { console.error('MindMapVisualization-Klasse ist nicht definiert!'); mindmapContainer.innerHTML = `

MindMap-Visualisierung konnte nicht geladen werden. Bitte laden Sie die Seite neu.

`; return; } // Erstelle die Mindmap-Visualisierung try { console.log('Versuche, MindMapVisualization zu erstellen...'); const mindmap = new MindMapVisualization('#mindmap-container', { height: 600, onNodeClick: handleNodeClick }); // Globale Referenz für die Zoom-Buttons erstellen window.mindmapInstance = mindmap; // Lade die Mindmap-Daten mindmap.loadData(); console.log('MindMapVisualization erfolgreich erstellt und geladen'); } catch (error) { console.error('Fehler beim Erstellen der MindMapVisualization:', error); mindmapContainer.innerHTML = `

Fehler beim Erstellen der Mindmap-Visualisierung:

${error.message}

`; return; } // Suchfunktion für die Mindmap const searchInput = document.getElementById('mindmap-search'); if (searchInput) { searchInput.addEventListener('input', function(e) { mindmap.filterBySearchTerm(e.target.value); }); } /** * Behandelt Klicks auf Mindmap-Knoten */ async function handleNodeClick(node) { if (!thoughtsContainer) return; // Zeige Lade-Animation thoughtsContainer.innerHTML = `
`; try { // Lade Gedanken für den ausgewählten Knoten const response = await fetch(`/api/nodes/${node.id}/thoughts`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const thoughts = await response.json(); // Gedanken anzeigen renderThoughts(thoughts, node.name); } catch (error) { console.error('Fehler beim Laden der Gedanken:', error); thoughtsContainer.innerHTML = `

Fehler beim Laden der Gedanken.

Bitte versuchen Sie es später erneut.

`; } } /** * Rendert die Gedanken in den Container */ function renderThoughts(thoughts, nodeName) { // Wenn keine Gedanken vorhanden sind if (thoughts.length === 0) { thoughtsContainer.innerHTML = `

Keine Gedanken für "${nodeName}" vorhanden.

`; // Event-Listener für den Button document.getElementById('add-thought-btn').addEventListener('click', () => { openAddThoughtModal(nodeName); }); return; } // Gedanken anzeigen thoughtsContainer.innerHTML = `

Gedanken zu "${nodeName}"

`; // Button-Event-Listener document.getElementById('add-thought-btn').addEventListener('click', () => { openAddThoughtModal(nodeName); }); // Gedanken-Karten rendern const thoughtsGrid = document.getElementById('thoughts-grid'); thoughts.forEach((thought, index) => { const card = createThoughtCard(thought); // Animation verzögern für gestaffeltes Erscheinen setTimeout(() => { card.classList.add('opacity-100'); card.classList.remove('opacity-0', 'translate-y-4'); }, index * 100); thoughtsGrid.appendChild(card); }); } /** * Erstellt eine Gedanken-Karte */ function createThoughtCard(thought) { const card = document.createElement('div'); card.className = 'card transition-all duration-300 opacity-0 translate-y-4 transform hover:shadow-lg border-l-4'; card.style.borderLeftColor = thought.color_code || '#4080ff'; // Karten-Inhalt card.innerHTML = `

${thought.title}

${thought.timestamp}

${thought.content}

${thought.keywords ? `
${thought.keywords.split(',').map(keyword => `${keyword.trim()}` ).join('')}
` : ''}
${thought.author}
`; return card; } /** * Öffnet das Modal zum Hinzufügen eines neuen Gedankens */ function openAddThoughtModal(nodeName) { // Node-Information extrahieren let nodeId, nodeTitle; if (typeof nodeName === 'string') { // Wenn nur ein String übergeben wurde nodeTitle = nodeName; // Versuche nodeId aus der Mindmap zu finden const nodeElement = d3.selectAll('.node-group').filter(d => d.name === nodeName); if (nodeElement.size() > 0) { nodeId = nodeElement.datum().id; } } else if (typeof nodeName === 'object') { // Wenn ein Node-Objekt übergeben wurde nodeId = nodeName.id; nodeTitle = nodeName.name; } else { console.error('Ungültiger Node-Parameter', nodeName); return; } // Modal-Struktur erstellen const modal = document.createElement('div'); modal.className = 'fixed inset-0 z-50 flex items-center justify-center p-4'; modal.innerHTML = `

Neuer Gedanke zu "${nodeTitle}"

`; document.body.appendChild(modal); // Focus auf das erste Feld setzen setTimeout(() => { modal.querySelector('#title').focus(); }, 100); // Event-Listener hinzufügen modal.querySelector('#modal-backdrop').addEventListener('click', closeModal); modal.querySelector('#close-modal-btn').addEventListener('click', closeModal); modal.querySelector('#cancel-btn').addEventListener('click', closeModal); // Farbauswahl-Event-Listener const colorInput = modal.querySelector('#color_code'); const predefinedColors = modal.querySelector('#predefined_colors'); predefinedColors.addEventListener('change', function() { colorInput.value = this.value; }); // Beziehungsmenü-Funktionalität const relationBtn = modal.querySelector('#open-relation-btn'); const relationMenu = modal.querySelector('#relation-menu'); relationBtn.addEventListener('click', function() { relationMenu.classList.toggle('hidden'); }); // Klick außerhalb des Menüs schließt es document.addEventListener('click', function(event) { if (!relationBtn.contains(event.target) && !relationMenu.contains(event.target)) { relationMenu.classList.add('hidden'); } }); // Beziehungstyp-Auswahl const relationTypeBtns = modal.querySelectorAll('.relation-type-btn'); const relationTypeInput = modal.querySelector('#relation_type'); relationTypeBtns.forEach(btn => { btn.addEventListener('click', function() { const relationType = this.dataset.type; relationTypeInput.value = relationType; // Sichtbare Anzeige aktualisieren relationBtn.innerHTML = ` ${this.innerText.trim()} `; // Menü schließen relationMenu.classList.add('hidden'); }); }); // Form-Submit-Handler const form = modal.querySelector('#add-thought-form'); form.addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(form); const thoughtData = { node_id: formData.get('node_id'), title: formData.get('title'), content: formData.get('content'), keywords: formData.get('keywords'), abstract: formData.get('abstract'), color_code: formData.get('color_code'), relation_type: formData.get('relation_type'), relation_target: formData.get('relation_target') }; try { const response = await fetch('/api/thoughts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(thoughtData) }); if (!response.ok) { throw new Error('Fehler beim Speichern des Gedankens.'); } // Modal schließen closeModal(); // Gedanken neu laden if (nodeId) { handleNodeClick({ id: nodeId, name: nodeTitle }); } // Erfolgsbenachrichtigung if (window.MindMap && window.MindMap.showNotification) { window.MindMap.showNotification('Gedanke erfolgreich gespeichert.', 'success'); } } catch (error) { console.error('Fehler beim Speichern:', error); if (window.MindMap && window.MindMap.showNotification) { window.MindMap.showNotification('Fehler beim Speichern des Gedankens.', 'error'); } } }); // Modal schließen function closeModal() { modal.classList.add('opacity-0'); setTimeout(() => { modal.remove(); }, 300); } } } /** * Füge globale Funktionen für das Mindmap-Objekt hinzu */ window.showComments = async function(thoughtId) { try { // Lade-Animation erstellen const modal = createModalWithLoading('Kommentare werden geladen...'); document.body.appendChild(modal); // Kommentare laden const response = await fetch(`/api/comments/${thoughtId}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const comments = await response.json(); // Modal mit Kommentaren aktualisieren updateModalWithComments(modal, comments, thoughtId); } catch (error) { console.error('Fehler beim Laden der Kommentare:', error); if (window.MindMap && window.MindMap.showNotification) { window.MindMap.showNotification('Fehler beim Laden der Kommentare.', 'error'); } else { alert('Fehler beim Laden der Kommentare.'); } } }; /** * Zeigt die Beziehungen eines Gedankens an */ window.showRelations = async function(thoughtId) { try { // Lade-Animation erstellen const modal = createModalWithLoading('Beziehungen werden geladen...'); document.body.appendChild(modal); // Beziehungen laden const response = await fetch(`/api/thoughts/${thoughtId}/relations`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const relations = await response.json(); // Modal mit Beziehungen aktualisieren updateModalWithRelations(modal, relations, thoughtId); } catch (error) { console.error('Fehler beim Laden der Beziehungen:', error); if (window.MindMap && window.MindMap.showNotification) { window.MindMap.showNotification('Fehler beim Laden der Beziehungen.', 'error'); } else { alert('Fehler beim Laden der Beziehungen.'); } } }; /** * Erstellt ein Modal mit Lade-Animation */ function createModalWithLoading(loadingText) { const modal = document.createElement('div'); modal.className = 'fixed inset-0 z-50 flex items-center justify-center p-4'; modal.innerHTML = `

${loadingText}

`; // Event-Listener zum Schließen modal.querySelector('#modal-backdrop').addEventListener('click', () => { modal.remove(); }); return modal; } /** * Aktualisiert das Modal mit Kommentaren */ function updateModalWithComments(modal, comments, thoughtId) { const modalContent = modal.querySelector('.glass-effect'); modalContent.innerHTML = `

Kommentare

${comments.length === 0 ? '
Keine Kommentare vorhanden.
' : comments.map(comment => `
${comment.author}
${comment.timestamp}

${comment.content}

`).join('') }
`; // Event-Listener hinzufügen modalContent.querySelector('#close-modal-btn').addEventListener('click', () => { modal.remove(); }); // Kommentar-Formular const form = modalContent.querySelector('#comment-form'); form.addEventListener('submit', async (e) => { e.preventDefault(); const content = form.elements.content.value; try { const response = await fetch('/api/comments', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ thought_id: thoughtId, content: content }) }); if (!response.ok) { throw new Error('Fehler beim Speichern des Kommentars.'); } // Modal schließen modal.remove(); // Erfolgsbenachrichtigung MindMap.showNotification('Kommentar erfolgreich gespeichert.', 'success'); } catch (error) { console.error('Fehler beim Speichern des Kommentars:', error); MindMap.showNotification('Fehler beim Speichern des Kommentars.', 'error'); } }); } /** * Aktualisiert das Modal mit Beziehungen */ function updateModalWithRelations(modal, relations, thoughtId) { const modalContent = modal.querySelector('.glass-effect'); modalContent.innerHTML = `

Beziehungen

${relations.length === 0 ? '
Keine Beziehungen vorhanden.
' : relations.map(relation => `
${relation.relation_type}
Ziel: Gedanke #${relation.target_id}
Erstellt von ${relation.created_by} am ${relation.created_at}
`).join('') }
`; // Event-Listener hinzufügen modalContent.querySelector('#close-modal-btn').addEventListener('click', () => { modal.remove(); }); // Beziehungs-Formular const form = modalContent.querySelector('#relation-form'); form.addEventListener('submit', async (e) => { e.preventDefault(); const formData = { source_id: thoughtId, target_id: parseInt(form.elements.target_id.value), relation_type: form.elements.relation_type.value }; try { const response = await fetch('/api/relations', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }); if (!response.ok) { throw new Error('Fehler beim Erstellen der Beziehung.'); } // Modal schließen modal.remove(); // Erfolgsbenachrichtigung MindMap.showNotification('Beziehung erfolgreich erstellt.', 'success'); } catch (error) { console.error('Fehler beim Erstellen der Beziehung:', error); MindMap.showNotification('Fehler beim Erstellen der Beziehung.', 'error'); } }); }