chore: Änderungen commited
This commit is contained in:
51
logs/app.log
51
logs/app.log
@@ -14,3 +14,54 @@
|
||||
2025-05-14 11:23:02,222 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:23:04,911 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:23:04,911 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:23:30,306 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:23:32,842 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:23:32,842 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:24:05,060 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:24:07,477 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:24:07,477 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:24:11,604 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:24:14,428 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:24:14,428 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:25:57,023 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
|
||||
Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
|
||||
Nicht angemeldet
|
||||
Traceback (most recent call last):
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\flask\app.py", line 1484, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\flask\app.py", line 1458, in dispatch_request
|
||||
self.raise_routing_exception(req)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\flask\app.py", line 1440, in raise_routing_exception
|
||||
raise request.routing_exception # type: ignore
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\flask\ctx.py", line 353, in match_request
|
||||
result = self.url_adapter.match(return_rule=True) # type: ignore
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\werkzeug\routing\map.py", line 655, in match
|
||||
raise NotFound() from None
|
||||
werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
|
||||
[in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:93]
|
||||
2025-05-14 11:25:57,023 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
|
||||
Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
|
||||
Nicht angemeldet
|
||||
Traceback (most recent call last):
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\flask\app.py", line 1484, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\flask\app.py", line 1458, in dispatch_request
|
||||
self.raise_routing_exception(req)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\flask\app.py", line 1440, in raise_routing_exception
|
||||
raise request.routing_exception # type: ignore
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\flask\ctx.py", line 353, in match_request
|
||||
result = self.url_adapter.match(return_rule=True) # type: ignore
|
||||
File "C:\Users\TTOMCZA.EMEA\AppData\Roaming\Python\Python313\site-packages\werkzeug\routing\map.py", line 655, in match
|
||||
raise NotFound() from None
|
||||
werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
|
||||
[in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:93]
|
||||
2025-05-14 11:27:26,252 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:27:26,419 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:27:28,763 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:27:28,763 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:27:28,854 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
2025-05-14 11:27:28,854 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
|
||||
|
||||
@@ -136,11 +136,7 @@ async function loadMindmapData(nodeId = null) {
|
||||
let errorData;
|
||||
try {
|
||||
errorData = await response.json();
|
||||
console.log('API-Fehler Details:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
errorData
|
||||
});
|
||||
console.log('API-Fehler Details:', errorData);
|
||||
} catch (e) {
|
||||
console.error('Fehler beim Parsen der Fehlerantwort:', e);
|
||||
errorData = {
|
||||
@@ -149,25 +145,26 @@ async function loadMindmapData(nodeId = null) {
|
||||
}
|
||||
|
||||
// Fehlerobjekt für die Benachrichtigung erstellen
|
||||
const errorMessage = {
|
||||
error: errorData.error || errorData.message || 'Unbekannter Fehler',
|
||||
details: errorData.details || null
|
||||
};
|
||||
const errorMessage = errorData.error || 'Unbekannter Fehler';
|
||||
|
||||
showUINotification(errorMessage, 'error');
|
||||
throw new Error(errorMessage.error);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Geladene Mindmap-Daten:', data);
|
||||
|
||||
if (!data.success) {
|
||||
const errorMessage = {
|
||||
error: data.error || 'Mindmap-Daten konnten nicht geladen werden',
|
||||
details: data.details || null
|
||||
};
|
||||
const errorMessage = data.error || 'Mindmap-Daten konnten nicht geladen werden';
|
||||
showUINotification(errorMessage, 'error');
|
||||
throw new Error(errorMessage.error);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
// Überprüfen, ob Nodes und Edges existieren
|
||||
if (!data.nodes || !data.edges) {
|
||||
const errorMessage = 'Ungültiges Datenformat: Nodes oder Edges fehlen';
|
||||
showUINotification(errorMessage, 'error');
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
// Erfolgreiche Antwort
|
||||
@@ -175,17 +172,10 @@ async function loadMindmapData(nodeId = null) {
|
||||
showUINotification('Mindmap-Daten erfolgreich geladen', 'success');
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Mindmap-Daten:', {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
nodeId
|
||||
});
|
||||
console.error('Fehler beim Laden der Mindmap-Daten:', error);
|
||||
|
||||
// Stelle sicher, dass wir eine aussagekräftige Fehlermeldung haben
|
||||
const errorMessage = {
|
||||
error: error.message || 'Unbekannter Fehler beim Laden der Mindmap-Daten',
|
||||
details: error.stack
|
||||
};
|
||||
const errorMessage = error.message || 'Unbekannter Fehler beim Laden der Mindmap-Daten';
|
||||
|
||||
showUINotification(errorMessage, 'error');
|
||||
throw error;
|
||||
@@ -754,609 +744,75 @@ function showFlash(message, type = 'info') {
|
||||
* @param {number} duration - Die Anzeigedauer in Millisekunden (Standard: 3000)
|
||||
*/
|
||||
function showUINotification(message, type = 'info', duration = 3000) {
|
||||
// Überprüfe und formatiere die Nachricht
|
||||
let displayMessage;
|
||||
if (typeof message === 'object') {
|
||||
if (message.message) {
|
||||
displayMessage = message.message;
|
||||
} else if (message.error) {
|
||||
displayMessage = message.error;
|
||||
} else if (message.details) {
|
||||
displayMessage = message.details;
|
||||
} else {
|
||||
console.error('Ungültiges Nachrichtenobjekt:', message);
|
||||
displayMessage = 'Ein unbekannter Fehler ist aufgetreten';
|
||||
}
|
||||
} else if (typeof message === 'string') {
|
||||
displayMessage = message;
|
||||
// Container erstellen, falls er nicht existiert
|
||||
let container = document.getElementById('notification-container');
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
container.id = 'notification-container';
|
||||
container.style.position = 'fixed';
|
||||
container.style.top = '1rem';
|
||||
container.style.right = '1rem';
|
||||
container.style.zIndex = '1000';
|
||||
container.style.maxWidth = '400px';
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
|
||||
// Benachrichtigung erstellen
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `notification notification-${type}`;
|
||||
notification.style.padding = '1rem';
|
||||
notification.style.marginBottom = '0.5rem';
|
||||
notification.style.borderRadius = '0.25rem';
|
||||
notification.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)';
|
||||
notification.style.position = 'relative';
|
||||
notification.style.opacity = '0';
|
||||
notification.style.transform = 'translateY(-20px)';
|
||||
notification.style.transition = 'all 0.3s ease-in-out';
|
||||
|
||||
// Farben nach Typ
|
||||
if (type === 'success') {
|
||||
notification.style.backgroundColor = '#059669';
|
||||
notification.style.color = '#ffffff';
|
||||
} else if (type === 'error') {
|
||||
notification.style.backgroundColor = '#DC2626';
|
||||
notification.style.color = '#ffffff';
|
||||
} else if (type === 'warning') {
|
||||
notification.style.backgroundColor = '#F59E0B';
|
||||
notification.style.color = '#ffffff';
|
||||
} else {
|
||||
console.error('Ungültige Nachricht für UI-Benachrichtigung:', message);
|
||||
displayMessage = 'Ein unbekannter Fehler ist aufgetreten';
|
||||
notification.style.backgroundColor = '#3B82F6';
|
||||
notification.style.color = '#ffffff';
|
||||
}
|
||||
|
||||
// Validiere den Typ
|
||||
const validTypes = ['info', 'success', 'warning', 'error'];
|
||||
if (!validTypes.includes(type)) {
|
||||
console.warn(`Ungültiger Benachrichtigungstyp: ${type}. Verwende 'info' als Fallback.`);
|
||||
type = 'info';
|
||||
}
|
||||
// Nachrichteninhalt formatieren
|
||||
let content = '';
|
||||
|
||||
// Validiere die Dauer
|
||||
if (typeof duration !== 'number' || duration < 1000 || duration > 10000) {
|
||||
console.warn(`Ungültige Dauer: ${duration}ms. Verwende 3000ms als Fallback.`);
|
||||
duration = 3000;
|
||||
}
|
||||
|
||||
// Zeige die Benachrichtigung an
|
||||
showFlash(displayMessage, type);
|
||||
|
||||
// Logging für Debugging-Zwecke
|
||||
console.log(`UI-Benachrichtigung [${type}]:`, displayMessage);
|
||||
}
|
||||
|
||||
// Hilfsfunktion zum Erstellen eines Flash-Containers, falls keiner existiert
|
||||
function createFlashContainer() {
|
||||
const container = document.createElement('div');
|
||||
container.id = 'flash-messages';
|
||||
container.className = 'fixed top-4 right-4 z-50 w-64';
|
||||
document.body.appendChild(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
// Funktion zum Laden der Subthemen
|
||||
async function loadSubthemes(node) {
|
||||
try {
|
||||
// Prüfe zuerst, ob die Node gültig ist
|
||||
if (!node || !node.id) {
|
||||
console.error('Ungültige Node beim Laden der Subthemen');
|
||||
showUINotification('Fehler: Ungültiger Knoten für Subthemen', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Zeige Ladebenachrichtigung
|
||||
showUINotification('Lade Subthemen...', 'info');
|
||||
console.log('Lade Subthemen für Node:', node.id());
|
||||
|
||||
// Lade die Daten für die Unterthemen
|
||||
const data = await loadMindmapData(node.id());
|
||||
if (!data || !data.nodes || !data.edges) {
|
||||
throw new Error('Ungültiges Datenformat: Subthemen-Daten fehlen oder sind unvollständig');
|
||||
}
|
||||
|
||||
// Markiere den aktuellen Knoten als erweitert
|
||||
node.data('expanded', true);
|
||||
|
||||
// Finde den Mindmap-Container
|
||||
let mindmapContainer = document.querySelector('.mindmap-container');
|
||||
if (!mindmapContainer) {
|
||||
// Falls der Container nicht existiert, versuche den cy-Container zu finden und erstelle einen Wrapper
|
||||
const cyContainer = document.getElementById('cy');
|
||||
if (!cyContainer) {
|
||||
throw new Error('Mindmap-Container nicht gefunden');
|
||||
if (typeof message === 'object' && message !== null) {
|
||||
// Wenn es ein Fehler-Objekt ist
|
||||
if (message.error) {
|
||||
content = message.error;
|
||||
if (message.details) {
|
||||
content += `<br><small>${message.details}</small>`;
|
||||
}
|
||||
|
||||
// Erstelle einen Container für die Mindmap-Seiten
|
||||
const parentElement = cyContainer.parentElement;
|
||||
mindmapContainer = document.createElement('div');
|
||||
mindmapContainer.className = 'mindmap-container';
|
||||
parentElement.insertBefore(mindmapContainer, cyContainer);
|
||||
parentElement.removeChild(cyContainer);
|
||||
mindmapContainer.appendChild(cyContainer);
|
||||
}
|
||||
|
||||
// Erstelle eine neue Seite für die Unterthemen
|
||||
const newPage = document.createElement('div');
|
||||
newPage.className = 'mindmap-page';
|
||||
newPage.setAttribute('data-parent-node', node.id());
|
||||
|
||||
// Erstelle den Header der Seite
|
||||
const header = document.createElement('div');
|
||||
header.className = 'mindmap-header';
|
||||
header.innerHTML = `
|
||||
<button class="back-button" onclick="goBack()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h2 class="mindmap-title">${node.data('label')}</h2>
|
||||
<div class="mindmap-actions">
|
||||
<button class="edit-button" onclick="enableMindmapEditing('${node.id()}')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
|
||||
</svg>
|
||||
<span>Bearbeiten</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Erstelle den Container für das neue Cytoscape
|
||||
const newCyContainer = document.createElement('div');
|
||||
newCyContainer.id = `cy-${node.id()}`;
|
||||
newCyContainer.className = 'mindmap-view';
|
||||
|
||||
// Füge die Elemente zur Seite hinzu
|
||||
newPage.appendChild(header);
|
||||
newPage.appendChild(newCyContainer);
|
||||
mindmapContainer.appendChild(newPage);
|
||||
|
||||
// Aktuelles Cy-Element ausblenden
|
||||
if (cy && cy.container()) {
|
||||
cy.container().style.display = 'none';
|
||||
}
|
||||
|
||||
// Initialisiere das neue Cytoscape
|
||||
const newCy = cytoscape({
|
||||
container: newCyContainer,
|
||||
elements: [
|
||||
// Knoten
|
||||
...data.nodes.map(node => ({
|
||||
data: {
|
||||
id: node.id,
|
||||
label: node.name || node.label,
|
||||
category: node.category,
|
||||
description: node.description,
|
||||
hasChildren: node.has_children,
|
||||
expanded: false,
|
||||
color: node.color_code || (node.category && mindmapConfig.categories[node.category]
|
||||
? mindmapConfig.categories[node.category].color
|
||||
: '#60a5fa'),
|
||||
fontColor: '#ffffff',
|
||||
fontSize: 16
|
||||
}
|
||||
})),
|
||||
// Kanten
|
||||
...data.edges.map(edge => ({
|
||||
data: {
|
||||
source: edge.source || edge.source_id,
|
||||
target: edge.target || edge.target_id,
|
||||
strength: edge.strength || 0.5
|
||||
}
|
||||
}))
|
||||
],
|
||||
style: [
|
||||
{
|
||||
selector: 'node',
|
||||
style: mindmapStyles.node.base
|
||||
},
|
||||
{
|
||||
selector: 'node[isCenter]',
|
||||
style: mindmapStyles.node.center
|
||||
},
|
||||
{
|
||||
selector: 'node:selected',
|
||||
style: mindmapStyles.node.selected
|
||||
},
|
||||
{
|
||||
selector: 'edge',
|
||||
style: mindmapStyles.edge.base
|
||||
}
|
||||
],
|
||||
layout: mindmapStyles.layout.base
|
||||
});
|
||||
|
||||
// Füge neuronale Eigenschaften zu allen Knoten hinzu
|
||||
newCy.nodes().forEach(node => {
|
||||
const data = node.data();
|
||||
// Verwende mindmapConfig für Kategorie-Farben oder einen Standardwert
|
||||
const categoryColor = data.category && mindmapConfig.categories[data.category]
|
||||
? mindmapConfig.categories[data.category].color
|
||||
: '#60a5fa';
|
||||
|
||||
node.data({
|
||||
...data,
|
||||
neuronSize: data.neuronSize || 8,
|
||||
neuronActivity: data.neuronActivity || 0.8,
|
||||
refractionPeriod: Math.random() * 300 + 700,
|
||||
threshold: Math.random() * 0.3 + 0.6,
|
||||
lastFired: 0,
|
||||
color: data.color || categoryColor
|
||||
});
|
||||
});
|
||||
|
||||
// Füge synaptische Eigenschaften zu allen Kanten hinzu
|
||||
newCy.edges().forEach(edge => {
|
||||
const data = edge.data();
|
||||
edge.data({
|
||||
...data,
|
||||
strength: data.strength || 0.5,
|
||||
conductionVelocity: Math.random() * 0.5 + 0.3,
|
||||
latency: Math.random() * 100 + 50
|
||||
});
|
||||
});
|
||||
|
||||
// Event-Listener für die neue Mindmap
|
||||
newCy.on('tap', 'node', async function(evt) {
|
||||
const clickedNode = evt.target;
|
||||
console.log('Node clicked in subtheme:', clickedNode.id(), 'hasChildren:', clickedNode.data('hasChildren'), 'expanded:', clickedNode.data('expanded'));
|
||||
|
||||
if (clickedNode.data('hasChildren') && !clickedNode.data('expanded')) {
|
||||
await loadSubthemes(clickedNode);
|
||||
}
|
||||
});
|
||||
|
||||
// Starte neuronale Aktivitätssimulation für die neue Mindmap
|
||||
startNeuralActivitySimulation(newCy);
|
||||
|
||||
// Speichere die Cytoscape-Instanz in einem globalen Array, damit wir sie später referenzieren können
|
||||
if (!window.subthemeCyInstances) {
|
||||
window.subthemeCyInstances = {};
|
||||
}
|
||||
window.subthemeCyInstances[node.id()] = newCy;
|
||||
|
||||
// Layout ausführen
|
||||
newCy.layout(mindmapStyles.layout.base).run();
|
||||
|
||||
// Zeige die neue Seite an
|
||||
newPage.style.display = 'block';
|
||||
|
||||
showUINotification('Subthemen erfolgreich geladen', 'success');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Subthemen:', error);
|
||||
showUINotification({
|
||||
error: 'Subthemen konnten nicht geladen werden',
|
||||
details: error.message
|
||||
}, 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Zurücknavigieren
|
||||
function goBack() {
|
||||
try {
|
||||
// Finde die aktuell angezeigte Mindmap-Seite
|
||||
const currentPage = document.querySelector('.mindmap-page:not([style*="display: none"])');
|
||||
if (!currentPage) {
|
||||
console.warn('Keine Mindmap-Seite gefunden, zu der zurückgekehrt werden kann');
|
||||
return;
|
||||
}
|
||||
|
||||
// Finde die übergeordnete Node ID
|
||||
const parentNodeId = currentPage.getAttribute('data-parent-node');
|
||||
if (!parentNodeId) {
|
||||
console.warn('Keine übergeordnete Node-ID gefunden, zeige die Hauptmindmap an');
|
||||
|
||||
// Blende das aktuelle Cy-Element aus
|
||||
if (window.cy && window.cy.container()) {
|
||||
window.cy.container().style.display = 'block';
|
||||
}
|
||||
|
||||
// Entferne die aktuelle Seite
|
||||
currentPage.style.display = 'none';
|
||||
setTimeout(() => {
|
||||
if (currentPage.parentNode) {
|
||||
currentPage.parentNode.removeChild(currentPage);
|
||||
}
|
||||
}, 300);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Navigiere zurück von Knoten:', parentNodeId);
|
||||
|
||||
// Entferne die aktuelle Cytoscape-Instanz aus dem Array
|
||||
if (window.subthemeCyInstances && window.subthemeCyInstances[parentNodeId]) {
|
||||
} else {
|
||||
// Versuche, das Objekt zu stringifizieren
|
||||
try {
|
||||
if (typeof window.subthemeCyInstances[parentNodeId].destroy === 'function') {
|
||||
window.subthemeCyInstances[parentNodeId].destroy();
|
||||
}
|
||||
delete window.subthemeCyInstances[parentNodeId];
|
||||
content = JSON.stringify(message);
|
||||
} catch (e) {
|
||||
console.error('Fehler beim Zerstören der Cytoscape-Instanz:', e);
|
||||
content = 'Objekt konnte nicht angezeigt werden';
|
||||
}
|
||||
}
|
||||
|
||||
// Prüfe, ob es eine übergeordnete Mindmap-Seite gibt
|
||||
const parentPage = document.querySelector(`.mindmap-page[data-parent-node]:not([data-parent-node="${parentNodeId}"])`);
|
||||
|
||||
if (parentPage) {
|
||||
// Wenn eine übergeordnete Seite gefunden wurde, zeige sie an
|
||||
parentPage.style.display = 'block';
|
||||
|
||||
// Entferne die aktuelle Seite
|
||||
currentPage.style.display = 'none';
|
||||
setTimeout(() => {
|
||||
if (currentPage.parentNode) {
|
||||
currentPage.parentNode.removeChild(currentPage);
|
||||
}
|
||||
}, 300);
|
||||
} else {
|
||||
// Wenn keine übergeordnete Seite gefunden wurde, zeige die Hauptmindmap an
|
||||
if (window.cy && window.cy.container()) {
|
||||
window.cy.container().style.display = 'block';
|
||||
}
|
||||
|
||||
// Entferne die aktuelle Seite
|
||||
currentPage.style.display = 'none';
|
||||
setTimeout(() => {
|
||||
if (currentPage.parentNode) {
|
||||
currentPage.parentNode.removeChild(currentPage);
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
showUINotification('Zurück zur übergeordneten Mindmap', 'info');
|
||||
} catch (error) {
|
||||
console.error('Fehler bei der Rücknavigation:', error);
|
||||
showUINotification('Fehler bei der Rücknavigation', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// CSS-Styles für die neue Seite
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.mindmap-page {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--bg-color, #1a1a1a);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.mindmap-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.back-button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem;
|
||||
margin-right: 1rem;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.mindmap-title {
|
||||
color: #fff;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mindmap-view {
|
||||
width: 100%;
|
||||
height: calc(100% - 4rem);
|
||||
}
|
||||
|
||||
/* Neuronale Effekte */
|
||||
.cy-container {
|
||||
background: linear-gradient(45deg, #1a1a1a, #2a2a2a);
|
||||
}
|
||||
|
||||
.cy-container node {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.cy-container node:hover {
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
|
||||
.cy-node-icon {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
z-index: 1001;
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 8px rgba(0,0,0,0.25);
|
||||
}
|
||||
|
||||
/* Verbesserte Flash-Benachrichtigungen */
|
||||
#flash-messages {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
max-width: 24rem;
|
||||
}
|
||||
|
||||
.flash-message {
|
||||
padding: 1rem 1.25rem;
|
||||
border-radius: 0.5rem;
|
||||
background: rgba(17, 24, 39, 0.95);
|
||||
color: #fff;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
transform: translateX(120%);
|
||||
opacity: 0;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.flash-message.show {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.flash-message.info {
|
||||
border-left: 4px solid #3b82f6;
|
||||
background: linear-gradient(to right, rgba(59, 130, 246, 0.1), rgba(17, 24, 39, 0.95));
|
||||
}
|
||||
|
||||
.flash-message.success {
|
||||
border-left: 4px solid #10b981;
|
||||
background: linear-gradient(to right, rgba(16, 185, 129, 0.1), rgba(17, 24, 39, 0.95));
|
||||
}
|
||||
|
||||
.flash-message.warning {
|
||||
border-left: 4px solid #f59e0b;
|
||||
background: linear-gradient(to right, rgba(245, 158, 11, 0.1), rgba(17, 24, 39, 0.95));
|
||||
}
|
||||
|
||||
.flash-message.error {
|
||||
border-left: 4px solid #ef4444;
|
||||
background: linear-gradient(to right, rgba(239, 68, 68, 0.1), rgba(17, 24, 39, 0.95));
|
||||
}
|
||||
|
||||
.flash-message::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(45deg,
|
||||
rgba(255, 255, 255, 0.1) 0%,
|
||||
rgba(255, 255, 255, 0) 100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.02); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
.flash-message.show {
|
||||
animation: pulse 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* Neuronale Effekte für Benachrichtigungen */
|
||||
.flash-message.info:hover {
|
||||
box-shadow: 0 0 15px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.flash-message.success:hover {
|
||||
box-shadow: 0 0 15px rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
|
||||
.flash-message.warning:hover {
|
||||
box-shadow: 0 0 15px rgba(245, 158, 11, 0.3);
|
||||
}
|
||||
|
||||
.flash-message.error:hover {
|
||||
box-shadow: 0 0 15px rgba(239, 68, 68, 0.3);
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Initialisiere die Mindmap beim Laden der Seite
|
||||
document.addEventListener('DOMContentLoaded', initializeMindmap);
|
||||
|
||||
// Funktion zum Aktivieren des Bearbeitungsmodus
|
||||
function enableMindmapEditing(nodeId) {
|
||||
try {
|
||||
console.log('Aktiviere Bearbeitungsmodus für Mindmap:', nodeId);
|
||||
|
||||
// Finde die relevante Cytoscape-Instanz
|
||||
let targetCy;
|
||||
if (nodeId) {
|
||||
// Für Unterthemen
|
||||
if (window.subthemeCyInstances && window.subthemeCyInstances[nodeId]) {
|
||||
targetCy = window.subthemeCyInstances[nodeId];
|
||||
} else {
|
||||
throw new Error(`Cytoscape-Instanz für Node ${nodeId} nicht gefunden`);
|
||||
}
|
||||
} else {
|
||||
// Für die Hauptmindmap
|
||||
targetCy = window.cy;
|
||||
}
|
||||
|
||||
if (!targetCy) {
|
||||
throw new Error('Keine aktive Cytoscape-Instanz gefunden');
|
||||
}
|
||||
|
||||
// Aktiviere Bearbeitungsmodus
|
||||
toggleEditingMode(targetCy, true);
|
||||
|
||||
// Zeige Bearbeitungssteuerungen an
|
||||
showEditingControls(nodeId);
|
||||
|
||||
showUINotification('Bearbeitungsmodus aktiviert', 'info');
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Aktivieren des Bearbeitungsmodus:', error);
|
||||
showUINotification('Fehler beim Aktivieren des Bearbeitungsmodus', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Deaktivieren des Bearbeitungsmodus
|
||||
function disableMindmapEditing(nodeId) {
|
||||
try {
|
||||
console.log('Deaktiviere Bearbeitungsmodus für Mindmap:', nodeId);
|
||||
|
||||
// Finde die relevante Cytoscape-Instanz
|
||||
let targetCy;
|
||||
if (nodeId) {
|
||||
// Für Unterthemen
|
||||
if (window.subthemeCyInstances && window.subthemeCyInstances[nodeId]) {
|
||||
targetCy = window.subthemeCyInstances[nodeId];
|
||||
}
|
||||
} else {
|
||||
// Für die Hauptmindmap
|
||||
targetCy = window.cy;
|
||||
}
|
||||
|
||||
if (!targetCy) {
|
||||
throw new Error('Keine aktive Cytoscape-Instanz gefunden');
|
||||
}
|
||||
|
||||
// Deaktiviere Bearbeitungsmodus
|
||||
toggleEditingMode(targetCy, false);
|
||||
|
||||
// Verstecke Bearbeitungssteuerungen
|
||||
hideEditingControls(nodeId);
|
||||
|
||||
showUINotification('Bearbeitungsmodus deaktiviert', 'info');
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Deaktivieren des Bearbeitungsmodus:', error);
|
||||
showUINotification('Fehler beim Deaktivieren des Bearbeitungsmodus', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Umschalten des Bearbeitungsmodus
|
||||
function toggleEditingMode(cy, enabled) {
|
||||
if (!cy) return;
|
||||
|
||||
if (enabled) {
|
||||
// Mache Knoten beweglich
|
||||
cy.nodes().ungrabify(false);
|
||||
|
||||
// Ändere den Cursor-Stil
|
||||
cy.container().classList.add('editing-mode');
|
||||
|
||||
// Aktiviere Ziehen und Ablegen
|
||||
cy.on('dragfree', 'node', function(event) {
|
||||
const node = event.target;
|
||||
console.log('Node verschoben:', node.id(), node.position());
|
||||
// Hier könnte man die neue Position in der Datenbank speichern
|
||||
});
|
||||
|
||||
// Aktiviere Doppelklick zum Bearbeiten
|
||||
cy.on('dblclick', 'node', function(event) {
|
||||
const node = event.target;
|
||||
editNodeProperties(node);
|
||||
});
|
||||
|
||||
// Aktiviere Rechtsklick-Menü
|
||||
cy.on('cxttap', 'node', function(event) {
|
||||
const node = event.target;
|
||||
showNodeContextMenu(node, event.renderedPosition);
|
||||
});
|
||||
|
||||
// Aktiviere Rechtsklick auf leeren Bereich zum Hinzufügen neuer Knoten
|
||||
cy.on('cxttap', function(event) {
|
||||
if (event.target === cy) {
|
||||
showAddNodeMenu(event.renderedPosition);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// String oder andere primitive Typen
|
||||
content = message;
|
||||
}
|
||||
|
||||
notification.innerHTML = content;
|
||||
|
||||
// Schließen-Button
|
||||
const closeButton = document.createElement('span');
|
||||
closeButton.innerHTML = '×';
|
||||
closeButton.style.position = 'absolute';
|
||||
// Deaktiviere Bearbeitungsfunktionen
|
||||
cy.nodes().grabify();
|
||||
cy.container().classList.remove('editing-mode');
|
||||
|
||||
Reference in New Issue
Block a user