Changeset 9eb6e1b in Klonkt for src/assets
- Timestamp:
- 09/30/2026 06:41:45 AM (4 hours ago)
- Branches:
- main
- Children:
- 86cfa1a
- Parents:
- 3ceaef6
- Location:
- src/assets/js/mod
- Files:
-
- 2 edited
-
authorize-interaction.js (modified) (1 diff)
-
chrome.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/assets/js/mod/authorize-interaction.js
r3ceaef6 r9eb6e1b 41 41 // ── volgend blok ── 42 42 43 /* Like/Boost toggle in place — POST via fetch, flip the button, stay on the page. */ 44 (function(){ 45 if (window.__fediReactWired) return; window.__fediReactWired = true; 46 document.addEventListener('submit', function(e){ 47 var f = e.target.closest && e.target.closest('.fedi-react-form'); 48 if (!f) return; 49 e.preventDefault(); 50 var btn = f.querySelector('button'); if (!btn || btn.disabled) return; 51 btn.disabled = true; 52 var body = new URLSearchParams(); 53 new FormData(f).forEach(function(v, k){ body.append(k, v); }); 54 fetch(f.action, { method: 'POST', body: body, headers: { 'X-Requested-With': 'fetch' }, credentials: 'same-origin' }) 55 .then(function(r){ return r.ok ? r.json() : null; }) 56 .then(function(j){ 57 if (j) { 58 var on = !!j.on; 59 btn.classList.toggle('is-on', on); 60 var lbl = btn.querySelector('.fedi-bigact-label'); 61 if (lbl) lbl.textContent = on ? (btn.getAttribute('data-on') || lbl.textContent) : (btn.getAttribute('data-off') || lbl.textContent); 62 } 63 }) 64 .catch(function(){}) 65 .then(function(){ btn.disabled = false; }); 66 }); 67 })(); 43 /* Waarderen en boosten ter plekke staat sinds de herbouw van de kaart in 44 chrome.js: de kaart staat nu ook in de zoekbalk, op elke pagina. */ 68 45 } -
src/assets/js/mod/chrome.js
r3ceaef6 r9eb6e1b 161 161 box.innerHTML = html; 162 162 } 163 var _sTimer; 163 // Een ADRES is geen zoekterm (shaer-utpi). Dezelfde regel als lookupUri in 164 // routes/search.js: een schema is verplicht, anders wordt zoeken naar 165 // "soundfabrics.nl" een netwerkverzoek. De server beslist daarna nog eens, 166 // met de rechten erbij; dit scheelt alleen een vraag die toch nee oplevert. 167 function lookupUri(q) { 168 if (!/^https?:\/\//i.test(q) || /\s/.test(q)) return null; 169 try { var u = new URL(q); return u.hostname.indexOf('.') < 0 ? null : u.href; } catch (e) { return null; } 170 } 171 function allLink(ov, q) { 172 var action = (ov && ov.getAttribute('data-action')) || '/search'; 173 return '<a class="ss-all" href="' + esc(action) + '?q=' + encodeURIComponent(q) + '">' + esc(_st().all) + '</a>'; 174 } 175 function fetchSuggest(box, q, ov, seq) { 176 var url = (ov && ov.getAttribute('data-suggest')) || '/search/suggest'; 177 fetch(url + '?q=' + encodeURIComponent(q)) 178 .then(function(r){ return r.ok ? r.json() : null; }) 179 .then(function(d){ if (d && seq === _sSeq) renderSuggest(box, d, q, ov); }) 180 .catch(function(){}); 181 } 182 // Elke toetsaanslag krijgt een volgnummer. Een ophaling van een andere 183 // server duurt soms seconden; zonder nummer overschrijft een traag antwoord 184 // op een oude vraag wat je inmiddels hebt getypt. 185 var _sTimer, _sSeq = 0; 164 186 document.addEventListener('input', function(e) { 165 187 var inp = e.target.closest && e.target.closest('#search-overlay input[name="q"]'); … … 168 190 if (!box) return; 169 191 var q = inp.value.trim(); 192 var seq = ++_sSeq; 170 193 clearTimeout(_sTimer); 171 194 if (q.length < 2) { box.innerHTML = ''; return; } 195 var ov = document.getElementById('search-overlay'); 196 var address = lookupUri(q); 197 if (!address) { _sTimer = setTimeout(function() { fetchSuggest(box, q, ov, seq); }, 200); return; } 198 // Een geplakt adres: de post zelf, niet de tekst van de link doorzocht. 199 box.innerHTML = '<div class="ss-remote-loading">' + esc(_st().looking) + '</div>'; 172 200 _sTimer = setTimeout(function() { 173 var ov = document.getElementById('search-overlay'); 174 var url = (ov && ov.getAttribute('data-suggest')) || '/search/suggest'; 175 fetch(url + '?q=' + encodeURIComponent(q)) 176 .then(function(r){ return r.ok ? r.json() : null; }) 177 .then(function(d){ if (d) renderSuggest(box, d, q, ov); }) 178 .catch(function(){}); 179 }, 200); 180 }); 181 // Click on a suggestion → close the overlay (the link/boost handles navigation). 201 var url = (ov && ov.getAttribute('data-remote')) || '/search/remote'; 202 fetch(url + '?q=' + encodeURIComponent(address), { credentials: 'same-origin', headers: { 'X-Requested-With': 'fetch' } }) 203 .then(function(r) { 204 if (seq !== _sSeq) return; 205 // 204: geen recht om op te halen (of toch geen adres). Dan is het 206 // gewoon een zoekterm en krijg je de gewone suggesties. 207 if (r.status === 204 || !r.ok) { fetchSuggest(box, q, ov, seq); return; } 208 return r.text().then(function(html) { if (seq === _sSeq) box.innerHTML = html + allLink(ov, q); }); 209 }) 210 .catch(function() { if (seq === _sSeq) fetchSuggest(box, q, ov, seq); }); 211 }, 300); 212 }); 213 // Een klik op een suggestie sluit de overlay, want de link gaat ergens heen. 214 // Behalve wat in een nieuw tabblad opent (het origineel, een profiel): dan 215 // blijf je hier, en hoort de kaart er nog te staan als je terugkomt. 182 216 document.addEventListener('click', function(e) { 183 if (e.target.closest && e.target.closest('#search-suggest a')) { var o = overlay(); if (o) o.hidden = true; } 217 var a = e.target.closest && e.target.closest('#search-suggest a'); 218 if (a && a.getAttribute('target') !== '_blank') { var o = overlay(); if (o) o.hidden = true; } 219 }); 220 })(); 221 222 // ── De kaart van een post van een andere server ───────────────────────── 223 // Staat hier en niet in authorize-interaction.js, want de kaart staat nu op 224 // drie plekken: de live-preview (elke pagina, via de zoekbalk), de zoekpagina 225 // en /authorize_interaction. Alles luistert op document, dus een kaart die 226 // later binnenkomt (de preview, een htmx-wissel) doet vanzelf mee. 227 (function() { 228 if (window.__remoteCardWired) return; window.__remoteCardWired = true; 229 230 // Waarderen en boosten ter plekke: POST via fetch, de knop omzetten, blijven 231 // waar je bent. Zonder JS doet het formulier hetzelfde met een omweg. 232 document.addEventListener('submit', function(e) { 233 var f = e.target.closest && e.target.closest('.fedi-react-form'); 234 if (!f) return; 235 e.preventDefault(); 236 var btn = f.querySelector('button'); if (!btn || btn.disabled) return; 237 btn.disabled = true; 238 var body = new URLSearchParams(); 239 new FormData(f).forEach(function(v, k) { body.append(k, v); }); 240 fetch(f.action, { method: 'POST', body: body, headers: { 'X-Requested-With': 'fetch' }, credentials: 'same-origin' }) 241 .then(function(r) { return r.ok ? r.json() : null; }) 242 .then(function(j) { 243 if (!j) return; 244 var on = !!j.on; 245 btn.classList.toggle('is-on', on); 246 btn.setAttribute('aria-pressed', on ? 'true' : 'false'); 247 var lbl = btn.querySelector('.rp-act-label'); 248 if (lbl) lbl.textContent = on ? (btn.getAttribute('data-on') || lbl.textContent) : (btn.getAttribute('data-off') || lbl.textContent); 249 }) 250 .catch(function() {}) 251 .then(function() { btn.disabled = false; }); 252 }); 253 254 // Antwoorden klapt open waar de kaart staat. Staat er geen venster (de 255 // preview), dan volgt de knop gewoon zijn link naar de volle pagina, met het 256 // venster daar al open. 257 document.addEventListener('click', function(e) { 258 var open = e.target.closest && e.target.closest('[data-rp-reply]'); 259 var close = !open && e.target.closest && e.target.closest('[data-rp-reply-close]'); 260 if (!open && !close) return; 261 var panel = document.getElementById('rp-reply'); 262 if (!panel) return; 263 e.preventDefault(); 264 var btn = document.querySelector('[data-rp-reply][aria-controls="rp-reply"]'); 265 var show = !!open && panel.hidden; 266 panel.hidden = !show; 267 if (btn) btn.setAttribute('aria-expanded', show ? 'true' : 'false'); 268 if (show) { 269 var ed = panel.querySelector('.re-editor, textarea'); 270 if (ed) ed.focus(); 271 // Op een telefoon staat het venster vaak onder de vouw. 272 if (panel.scrollIntoView) panel.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); 273 } else if (btn) { 274 btn.focus(); 275 } 184 276 }); 185 277 })();
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)