📚 Improved documentation and logs structure for better maintainability and troubleshooting. 🖥️🔍
This commit is contained in:
@ -10,6 +10,10 @@ class GlassmorphismNotificationSystem {
|
||||
this.soundEnabled = localStorage.getItem('myp-notification-sound') !== 'false';
|
||||
this.animationsEnabled = !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
// Callback-Registry für Actions hinzufügen
|
||||
this.actionCallbacks = new Map();
|
||||
this.callbackCounter = 0;
|
||||
|
||||
this.init();
|
||||
this.setupGlobalFunctions();
|
||||
this.injectStyles();
|
||||
@ -49,6 +53,9 @@ class GlassmorphismNotificationSystem {
|
||||
window.showPersistentAlert = this.showPersistentAlert.bind(this);
|
||||
window.showConfirmationToast = this.showConfirmationToast.bind(this);
|
||||
window.showProgressToast = this.showProgressToast.bind(this);
|
||||
|
||||
// Globale Callback-Ausführungsfunktion
|
||||
window.executeNotificationCallback = this.executeCallback.bind(this);
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
@ -162,14 +169,23 @@ class GlassmorphismNotificationSystem {
|
||||
}
|
||||
|
||||
createActionButtons(actions, toastId) {
|
||||
return actions.map(action => `
|
||||
<button class="toast-action-btn toast-action-${action.type || 'secondary'}"
|
||||
onclick="${action.onClick}; ${action.closeAfter !== false ? `glassNotificationSystem.closeToast('${toastId}')` : ''}"
|
||||
title="${action.title || action.text}">
|
||||
${action.icon ? `<svg class="w-4 h-4">${action.icon}</svg>` : ''}
|
||||
${action.text}
|
||||
</button>
|
||||
`).join('');
|
||||
return actions.map(action => {
|
||||
// Callback in Registry speichern falls vorhanden
|
||||
let callbackId = '';
|
||||
if (action.callback && typeof action.callback === 'function') {
|
||||
callbackId = `callback-${++this.callbackCounter}`;
|
||||
this.actionCallbacks.set(callbackId, action.callback);
|
||||
}
|
||||
|
||||
return `
|
||||
<button class="toast-action-btn toast-action-${action.type || 'secondary'}"
|
||||
onclick="glassNotificationSystem.handleActionClick('${callbackId}', '${toastId}', ${action.closeAfter !== false})"
|
||||
title="${action.title || action.text}">
|
||||
${action.icon ? `<svg class="w-4 h-4">${action.icon}</svg>` : ''}
|
||||
${action.text}
|
||||
</button>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
getIconSvg(type) {
|
||||
@ -299,6 +315,14 @@ class GlassmorphismNotificationSystem {
|
||||
}
|
||||
|
||||
this.notifications.delete(toastId);
|
||||
|
||||
// Alle zugehörigen Callbacks löschen
|
||||
this.actionCallbacks.forEach((callback, callbackId) => {
|
||||
if (callbackId.includes(toastId)) {
|
||||
this.actionCallbacks.delete(callbackId);
|
||||
}
|
||||
});
|
||||
|
||||
this.repositionAllToasts();
|
||||
}
|
||||
|
||||
@ -331,21 +355,49 @@ class GlassmorphismNotificationSystem {
|
||||
* Spezielle Toast-Typen
|
||||
*/
|
||||
showConfirmationToast(message, onConfirm, onCancel = null, options = {}) {
|
||||
const confirmCallback = () => {
|
||||
if (typeof onConfirm === 'function') {
|
||||
try {
|
||||
onConfirm();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Ausführen der Bestätigungslogik:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const cancelCallback = () => {
|
||||
if (typeof onCancel === 'function') {
|
||||
try {
|
||||
onCancel();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Ausführen der Abbruchlogik:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const actions = [
|
||||
{
|
||||
text: options.confirmText || 'Bestätigen',
|
||||
type: 'primary',
|
||||
callback: confirmCallback,
|
||||
closeAfter: true
|
||||
}
|
||||
];
|
||||
|
||||
// Cancel-Button nur hinzufügen wenn Callback vorhanden ist
|
||||
if (onCancel || options.cancelText) {
|
||||
actions.push({
|
||||
text: options.cancelText || 'Abbrechen',
|
||||
type: 'secondary',
|
||||
callback: cancelCallback,
|
||||
closeAfter: true
|
||||
});
|
||||
}
|
||||
|
||||
return this.showToast(message, 'warning', 0, {
|
||||
persistent: true,
|
||||
title: options.title || 'Bestätigung erforderlich',
|
||||
actions: [
|
||||
{
|
||||
text: options.confirmText || 'Bestätigen',
|
||||
type: 'primary',
|
||||
onClick: `(${onConfirm.toString()})()`
|
||||
},
|
||||
{
|
||||
text: options.cancelText || 'Abbrechen',
|
||||
type: 'secondary',
|
||||
onClick: onCancel ? `(${onCancel.toString()})()` : ''
|
||||
}
|
||||
],
|
||||
actions: actions,
|
||||
...options
|
||||
});
|
||||
}
|
||||
@ -1485,6 +1537,43 @@ class GlassmorphismNotificationSystem {
|
||||
|
||||
document.head.appendChild(styles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Behandelt Action-Button-Klicks
|
||||
*/
|
||||
handleActionClick(callbackId, toastId, shouldClose = true) {
|
||||
// Callback ausführen falls vorhanden
|
||||
if (callbackId && this.actionCallbacks.has(callbackId)) {
|
||||
const callback = this.actionCallbacks.get(callbackId);
|
||||
try {
|
||||
callback();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Ausführen des Action-Callbacks:', error);
|
||||
}
|
||||
// Callback nach Ausführung löschen
|
||||
this.actionCallbacks.delete(callbackId);
|
||||
}
|
||||
|
||||
// Toast schließen falls gewünscht
|
||||
if (shouldClose) {
|
||||
this.closeToast(toastId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Für Rückwärtskompatibilität - führt Callback-Funktionen aus
|
||||
*/
|
||||
executeCallback(callbackId) {
|
||||
if (this.actionCallbacks.has(callbackId)) {
|
||||
const callback = this.actionCallbacks.get(callbackId);
|
||||
try {
|
||||
callback();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Ausführen des Callbacks:', error);
|
||||
}
|
||||
this.actionCallbacks.delete(callbackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Globale Instanz erstellen
|
||||
|
@ -485,16 +485,25 @@ function updateStatsCounter(elementId, value, animate = true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sichere Wert-Validierung hinzufügen
|
||||
if (value === null || value === undefined) {
|
||||
console.warn(`Ungültiger Wert für Element '${elementId}':`, value);
|
||||
value = 0; // Fallback-Wert
|
||||
}
|
||||
|
||||
if (animate) {
|
||||
// Animierte Zählung
|
||||
const currentValue = parseInt(element.textContent.replace(/[^\d]/g, '')) || 0;
|
||||
const targetValue = parseInt(value.toString().replace(/[^\d]/g, '')) || 0;
|
||||
|
||||
if (currentValue !== targetValue) {
|
||||
animateCounter(element, currentValue, targetValue, value.toString());
|
||||
// Sichere String-Konvertierung
|
||||
const finalTextValue = value !== null && value !== undefined ? value.toString() : '0';
|
||||
animateCounter(element, currentValue, targetValue, finalTextValue);
|
||||
}
|
||||
} else {
|
||||
element.textContent = value;
|
||||
// Sichere Zuweisung ohne Animation
|
||||
element.textContent = value !== null && value !== undefined ? value.toString() : '0';
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,6 +511,26 @@ function updateStatsCounter(elementId, value, animate = true) {
|
||||
* Animierte Counter-Funktion
|
||||
*/
|
||||
function animateCounter(element, start, end, finalText) {
|
||||
// Sichere Parameter-Validierung
|
||||
if (!element) {
|
||||
console.warn('animateCounter: Kein gültiges Element übergeben');
|
||||
return;
|
||||
}
|
||||
|
||||
// Sichere finalText-Validierung mit optimiertem Logging
|
||||
if (typeof finalText !== 'string') {
|
||||
// Nur bei problematischen Werten warnen (null, undefined, objects)
|
||||
if (finalText === null || finalText === undefined || (typeof finalText === 'object' && finalText !== null)) {
|
||||
console.warn('animateCounter: Problematischer finalText-Wert:', finalText);
|
||||
}
|
||||
// Normale Numbers stille konvertieren
|
||||
finalText = finalText !== null && finalText !== undefined ? String(finalText) : '0';
|
||||
}
|
||||
|
||||
// Sichere start/end-Validierung
|
||||
start = parseInt(start) || 0;
|
||||
end = parseInt(end) || 0;
|
||||
|
||||
const duration = 1000; // 1 Sekunde
|
||||
const startTime = performance.now();
|
||||
|
||||
@ -513,16 +542,28 @@ function animateCounter(element, start, end, finalText) {
|
||||
const easeOut = 1 - Math.pow(1 - progress, 3);
|
||||
const currentValue = Math.round(start + (end - start) * easeOut);
|
||||
|
||||
if (finalText.includes('%')) {
|
||||
element.textContent = currentValue + '%';
|
||||
} else {
|
||||
// Sichere includes-Prüfung
|
||||
try {
|
||||
if (typeof finalText === 'string' && finalText.includes('%')) {
|
||||
element.textContent = currentValue + '%';
|
||||
} else {
|
||||
element.textContent = currentValue;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('animateCounter: Fehler bei finalText.includes:', error, 'finalText:', finalText);
|
||||
element.textContent = currentValue;
|
||||
}
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(updateCounter);
|
||||
} else {
|
||||
element.textContent = finalText;
|
||||
// Sichere Zuweisung des finalen Wertes
|
||||
try {
|
||||
element.textContent = finalText;
|
||||
} catch (error) {
|
||||
console.warn('animateCounter: Fehler bei finaler Zuweisung:', error);
|
||||
element.textContent = String(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,20 +161,43 @@ class PrinterMonitor {
|
||||
// Drucker-Daten aktualisieren
|
||||
this.printers.clear();
|
||||
|
||||
// Null-Check für data.printers hinzufügen
|
||||
// Flexible Datenextraktion für verschiedene API-Response-Strukturen
|
||||
let printersData = null;
|
||||
|
||||
if (data && data.printers && typeof data.printers === 'object') {
|
||||
Object.values(data.printers).forEach(printer => {
|
||||
this.printers.set(printer.id, {
|
||||
...printer,
|
||||
statusInfo: this.statusCategories[printer.status] || this.statusCategories['offline']
|
||||
});
|
||||
// Alte Struktur: data.printers
|
||||
printersData = data.printers;
|
||||
} else if (data && data.status && typeof data.status === 'object') {
|
||||
// Neue Struktur: data.status
|
||||
printersData = data.status;
|
||||
} else if (data && typeof data === 'object' && !data.success && !data.error) {
|
||||
// Direkte Drucker-Daten ohne Wrapper
|
||||
printersData = data;
|
||||
}
|
||||
|
||||
if (printersData && typeof printersData === 'object') {
|
||||
// Drucker-Daten verarbeiten
|
||||
Object.values(printersData).forEach(printer => {
|
||||
// Sichere Validierung der Drucker-Objekte
|
||||
if (printer && typeof printer === 'object' && printer.id) {
|
||||
this.printers.set(printer.id, {
|
||||
...printer,
|
||||
statusInfo: this.statusCategories[printer.status] || this.statusCategories['offline']
|
||||
});
|
||||
} else {
|
||||
console.warn('⚠️ Ungültiges Drucker-Objekt übersprungen:', printer);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`✅ ${this.printers.size} Drucker erfolgreich verarbeitet`);
|
||||
} else {
|
||||
console.warn('⚠️ Keine gültigen Drucker-Daten erhalten:', data);
|
||||
// Benachrichtige Callbacks über Fehler
|
||||
console.warn('⚠️ Keine gültigen Drucker-Daten in Response-Struktur gefunden');
|
||||
console.debug('Response-Struktur:', data);
|
||||
|
||||
// Benachrichtige Callbacks über fehlende Daten (aber nicht als Fehler)
|
||||
this.notifyCallbacks({
|
||||
type: 'error',
|
||||
message: 'Ungültige Drucker-Daten erhalten',
|
||||
type: 'warning',
|
||||
message: 'Keine Drucker-Daten verfügbar',
|
||||
data: data
|
||||
});
|
||||
return;
|
||||
|
Reference in New Issue
Block a user