Changeset dbde7f8 in Klonkt for src/views/partials/topnav.ejs


Ignore:
Timestamp:
06/17/2026 03:48:04 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
125e0e1
Parents:
93d6345
Message:

Fix: theme toggle stops working after htmx navigation (stacked listeners)

The topnav is in the OOB-swapped chrome, so its <script> ran again on EVERY
htmx nav → the body click listener for the theme toggle stacked → toggle fired
2× = no net change. Now: one-time guard (window.pcmsChromeWired) + everything
via event delegation on body/document (works for OOB-inserted buttons too). Search
overlay + dropdown-close likewise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/views/partials/topnav.ejs

    r93d6345 rdbde7f8  
    173173<script>
    174174(function() {
    175   // Theme toggle (works for both mobile + desktop buttons)
     175  // EÉN keer bedraden. Deze chrome (topnav) wordt bij htmx-navigatie out-of-band
     176  // opnieuw ingevoegd → zonder deze guard zou dit script bij elke navigatie EXTRA
     177  // listeners stapelen, waardoor de thema-toggle 2× (of vaker) vuurde = geen netto
     178  // wisseling ("toggle werkt niet meer"). Alles hieronder is event-delegatie op
     179  // body/document, dus het werkt ook voor knoppen die ná deze run (OOB) verschijnen.
     180  if (window.__pcmsChromeWired) return;
     181  window.__pcmsChromeWired = true;
     182
    176183  function toggleTheme() {
    177     const cur = document.documentElement.getAttribute('data-theme') || 'dark';
    178     const next = cur === 'dark' ? 'light' : 'dark';
     184    var cur = document.documentElement.getAttribute('data-theme') || 'dark';
     185    var next = cur === 'dark' ? 'light' : 'dark';
    179186    document.documentElement.setAttribute('data-theme', next);
    180187    try { localStorage.setItem('pcms-theme', next); } catch (e) {}
    181188  }
    182   // Theme toggle — event delegation so it works for ANY button with the
    183   // matching ids, even ones rendered later in the page (footer is below
    184   // topnav in source order, so getElementById would have returned null
    185   // when this IIFE ran).
     189  function overlay() { return document.getElementById('search-overlay'); }
     190  function openSearch() { var o = overlay(); if (o) { o.hidden = false; var i = o.querySelector('input'); if (i) i.focus(); } }
     191  function closeSearch() { var o = overlay(); if (o) o.hidden = true; }
     192
    186193  document.body.addEventListener('click', function(e) {
    187     const btn = e.target.closest(
    188       '#theme-toggle, #theme-toggle-mobile, #theme-toggle-footer'
    189     );
    190     if (btn) toggleTheme();
     194    if (e.target.closest('#theme-toggle, #theme-toggle-mobile, #theme-toggle-footer')) { toggleTheme(); return; }
     195    if (e.target.closest('#search-toggle')) { openSearch(); return; }
     196    if (e.target.closest('#search-close')) { closeSearch(); return; }
     197    // Gebruikersmenu sluiten bij klik erbuiten.
     198    var open = document.querySelector('.user-menu[open]');
     199    if (open && !open.contains(e.target)) open.removeAttribute('open');
    191200  });
    192201
    193   // Search overlay
    194   const overlay = document.getElementById('search-overlay');
    195   document.getElementById('search-toggle')?.addEventListener('click', function() {
    196     if (overlay) {
    197       overlay.hidden = false;
    198       const inp = overlay.querySelector('input');
    199       if (inp) inp.focus();
    200     }
    201   });
    202   document.getElementById('search-close')?.addEventListener('click', function() {
    203     if (overlay) overlay.hidden = true;
    204   });
    205202  document.addEventListener('keydown', function(e) {
    206     if (e.key === 'Escape' && overlay && !overlay.hidden) overlay.hidden = true;
    207   });
    208 
    209   // Close user dropdown on outside click
    210   document.addEventListener('click', function(e) {
    211     const open = document.querySelector('.user-menu[open]');
    212     if (open && !open.contains(e.target)) open.removeAttribute('open');
     203    if (e.key === 'Escape') { var o = overlay(); if (o && !o.hidden) o.hidden = true; }
    213204  });
    214205})();
Note: See TracChangeset for help on using the changeset viewer.