Changeset e64a49b in Klonkt for src/views/pages/messages.ejs


Ignore:
Timestamp:
08/07/2026 12:24:02 PM (5 weeks ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
0db68bd
Parents:
20ae7b0
git-author:
Robin <roboburr@…> (08/07/2026 12:24:00 PM)
git-committer:
roboburr <roboburr@…> (08/07/2026 12:24:02 PM)
Message:

Berichten uit inline script naar een module (shaer-bqr, stap 2)

De enige bevestigde stukke plek. Kwam je hier via een link BINNEN de site, dan
arriveerde het script via htmx met een nonce die het document niet kent, en
weigerde de CSP het (shaer-0i6). Chips, zoeken en het in-/uitklappen deden dan
niets, en de reply-editor laadde niet -- dat was Barts melding.

Een pagina vraagt nu om zijn module met pageJs; de shell zet dat op body[data-js]
en de bootstrap importeert het. De waarde wordt een PAD, dus hij gaat door
/[a-z0-9 -]*$/ voordat hij de locals in mag.

TWEE DINGEN MOESTEN VERANDEREN, en niet omdat de code fout was: een module leeft
anders dan een inline script.

NIETS VASTHOUDEN het inline script pakte .msg-list, #msg-q en .msg-nomatch

een keer bij het inladen. Een module wordt per document maar
EEN keer geimporteerd, dus wie Berichten verlaat en
terugkomt houdt verwijzingen over naar elementen die er niet
meer zijn. Nu per keer opzoeken, en de invoerluisteraar
gedelegeerd in plaats van op het veld zelf.

OPNIEUW INDEXEREN bij binnenkomst op de pagina, niet alleen bij "meer laden".

Anders is de lijst na een navigatie niet geindexeerd en
filtert het zoeken op een lege verzameling.

Dat eerste is precies de val waar de chrome-partials al een comment over hebben
staan ("a once-captured reference goes stale"), en het geldt hier dubbel omdat
een module niet opnieuw draait.

Templates compileren, suite 556/556.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/views/pages/messages.ejs

    r20ae7b0 re64a49b  
    6060</div>
    6161
    62 <script>
    63 (function () {
    64   if (window.__msgWired) return; window.__msgWired = true;
    65 
    66   // Filtering: kind chip AND free-text search, combined in JS (search over the
    67   // sender and the rendered message text). Empty search + "all" = show all.
    68   var list = document.querySelector('.msg-list');
    69   var noMatch = document.querySelector('.msg-nomatch');
    70   var q = document.getElementById('msg-q');
    71   var kind = 'all';
    72   var items = [];
    73   function indexItem(li) {
    74     // Een draad indexeren op zijn eerste bubbel zou de rest onvindbaar maken,
    75     // dus daar nemen we de hele tekst; losse regels blijven gericht geindexeerd.
    76     if (li.classList.contains('msg-thread')) {
    77       li._search = ((li.getAttribute('data-who') || '') + ' ' + li.textContent).toLowerCase();
    78       return;
    79     }
    80     // Index once: sender + message body + linked post title + poll text.
    81     var body = li.querySelector('.msg-content');
    82     var post = li.querySelector('.msg-post');
    83     var poll = li.querySelector('.msg-poll');
    84     li._search = ((li.getAttribute('data-who') || '') + ' ' +
    85       (body ? body.textContent : '') + ' ' + (post ? post.textContent : '') + ' ' +
    86       (poll ? poll.textContent : '')).toLowerCase();
    87   }
    88   // Re-collect + index; called on load and after each "Load more" append so new
    89   // items join the filter/search (and inherit the active chip via apply()).
    90   function reindex() {
    91     items = list ? Array.prototype.slice.call(list.querySelectorAll(':scope > .msg-item')) : [];
    92     items.forEach(function (li) { if (!li._search) indexItem(li); });
    93   }
    94   reindex();
    95   function apply() {
    96     if (!list) return;
    97     var term = (q && q.value || '').trim().toLowerCase();
    98     var shown = 0;
    99     items.forEach(function (li) {
    100       var ok = (kind === 'all' || li.getAttribute('data-kind') === kind) &&
    101         (!term || li._search.indexOf(term) !== -1);
    102       li.style.display = ok ? '' : 'none';
    103       // Een treffer die in een dichtgeklapt gesprek zit, laat anders alleen de
    104       // naam zien: je zoekt iets, het staat er, en je ziet het niet. Zolang er
    105       // gezocht wordt gaat zo'n gesprek open; daarna keert hij terug naar de
    106       // stand die de lezer zelf koos.
    107       if (li.classList.contains('msg-thread')) {
    108         li.classList.toggle('is-search-open', !!term && ok);
    109       }
    110       if (ok) shown++;
    111     });
    112     if (noMatch) noMatch.hidden = shown !== 0;
    113   }
    114   // In- en uitklappen door op de tegenpartij te tikken (Barts aanwijzing).
    115   // Gedelegeerd, zodat draden die via "meer laden" binnenkomen het vanzelf ook
    116   // doen. De stand leeft alleen in deze pagina: standaard uitgeklapt, en na een
    117   // herlading weer. Dat is bewust -- een gesprek dat je gisteren dichtklapte
    118   // stilhouden is niet hetzelfde als het opruimen van je scherm van nu.
    119   document.addEventListener('click', function (e) {
    120     var who = e.target.closest('.msg-thread-who'); if (!who) return;
    121     var li = who.closest('.msg-thread'); if (!li) return;
    122     var dicht = li.classList.toggle('is-collapsed');
    123     who.setAttribute('aria-expanded', dicht ? 'false' : 'true');
    124   });
    125   document.addEventListener('click', function (e) {
    126     var chip = e.target.closest('.msg-chip'); if (!chip) return;
    127     kind = chip.getAttribute('data-show');
    128     document.querySelectorAll('.msg-chip').forEach(function (c) { c.classList.toggle('is-on', c === chip); });
    129     apply();
    130   });
    131   if (q) q.addEventListener('input', apply);
    132   // After a "Load more" append (htmx), index the new rows and re-apply the filter.
    133   document.body.addEventListener('htmx:afterSettle', function (e) {
    134     if (e.target && e.target.id === 'msg-list') { reindex(); apply(); }
    135   });
    136 
    137   var a = document.getElementById('fedi-bm-btn');
    138   if (a) {
    139     a.setAttribute('href', "javascript:void(window.open('" + location.origin + "/authorize_interaction?uri='+encodeURIComponent(window.location.href)))");
    140     a.addEventListener('click', function (e) { e.preventDefault(); a.classList.add('nudge'); setTimeout(function(){ a.classList.remove('nudge'); }, 600); });
    141   }
    142 })();
    143 </script>
     62<%# Filteren, zoeken en het in-/uitklappen zitten in assets/js/mod/messages.js.
     63    Inline script hier wordt door de CSP geweigerd zodra je deze pagina via een
     64    link BINNEN de site opent -- zie shaer-0i6. De shell laadt de module op
     65    body[data-js]; deze pagina vraagt erom met pageJs (routes/posts.js). %>
    14466
    14567<style>
Note: See TracChangeset for help on using the changeset viewer.