fix: resolve event-listener leaks and CSS gaps found in code quality audit

- notes.js (Critical): move grid click listener from renderGrid() to
  render() — was re-registered on every save/pin/delete, causing
  multiple API calls per user action after several interactions
- dashboard.js (Major): introduce AbortController (_fabController) so
  the anonymous document click listener from initFab() is cancelled on
  each new render() cycle; also remove the redundant initFab() call on
  the skeleton render
- layout.css (Major): extend .label selector to include .form-label,
  covering usage in notes.js and settings.js without a mass-rename
- test-modal-utils.js (Major): 12 unit tests for wireBlurValidation,
  btnSuccess, btnError; registered as test:modal-utils in package.json
- notes.js (Minor): add btnError() shake feedback to save error handler
- calendar.js (Minor): add popup.isConnected guard to closePopup so
  the listener self-removes correctly after navigation without a click

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ulas
2026-03-30 22:26:49 +02:00
parent 36de5fa477
commit 3e25339c86
7 changed files with 221 additions and 25 deletions
+9 -4
View File
@@ -6,6 +6,9 @@
import { api } from '/api.js';
// Hält den AbortController des aktuellen FAB-Listeners — wird bei jedem render() erneuert.
let _fabController = null;
// --------------------------------------------------------
// Hilfsfunktionen
// --------------------------------------------------------
@@ -339,7 +342,7 @@ function renderFab() {
`;
}
function initFab(container) {
function initFab(container, signal) {
const fabMain = container.querySelector('#fab-main');
const fabActions = container.querySelector('#fab-actions');
if (!fabMain) return;
@@ -368,7 +371,7 @@ function initFab(container) {
});
});
document.addEventListener('click', () => { if (open) toggleFab(false); });
document.addEventListener('click', () => { if (open) toggleFab(false); }, { signal });
}
// --------------------------------------------------------
@@ -395,6 +398,9 @@ function wireLinks(container) {
// --------------------------------------------------------
export async function render(container, { user }) {
_fabController?.abort();
_fabController = new AbortController();
container.innerHTML = `
<div class="dashboard">
<div class="dashboard__grid">
@@ -412,7 +418,6 @@ export async function render(container, { user }) {
</div>
${renderFab()}
`;
initFab(container);
let data = { upcomingEvents: [], urgentTasks: [], todayMeals: [], pinnedNotes: [] };
let weather = null;
@@ -455,6 +460,6 @@ export async function render(container, { user }) {
`;
wireLinks(container);
initFab(container);
initFab(container, _fabController.signal);
if (window.lucide) window.lucide.createIcons();
}