source: Klonkt/src/assets/js/mod/news.js@ a8364ee

main
Last change on this file since a8364ee was a8364ee, checked in by Robin <roboburr@…>, 5 weeks ago

Alle element-bedrade modules herstarten per paginawissel (shaer-5s1, vervolg)

Het recept van 4b5db37, toegepast op de rest van de familie. Twaalf modules
exporteren nu init(): download (de auto-start liep alleen bij import, dus na
een htmx-bezoek startte er niets), auth-register, admin-settings, admin-epk,
admin-paid, admin-help, admin-push, admin-site-edit, authorize-interaction,
paid-gate, paid-passkey en news.

Twee verdienen een woord:

authorize-interaction blok 1 bedraadde een element achter een WINDOW-vlag:

na een swap is de knop een nieuw element en
blokkeerde de vlag het herbedraden voorgoed. De vlag
zit nu op het element zelf.

news de gif- en lees-meer-scanners claimden in hun

commentaar per render te draaien, maar deden dat als
module niet meer. Ze zijn nu benoemde functies:
init() draait ze per navigatie, en een gedelegeerde
htmx:afterSettle draait ze ook na feed-paginering --
binnengehaalde items kregen anders geen lees-meer en
geen gif-gedrag.

Bewust ONaangeraakt, met reden: chrome (gedelegeerd, en de profile-sheet
staat BUITEN de geswapte #pcms-chrome dus zijn element-referenties blijven
geldig), post en messages (gedelegeerd; messages herstart zichzelf al via
pcmsNav), track-editor en playlist-editor (gedelegeerd / globale functie).

Co-Authored-By: Claude Opus 5 <noreply@…>

  • Property mode set to 100644
File size: 7.5 KB
Line 
1// De Krant -- verplaatst uit inline script, shaer-bqr.
2//
3// Inline script wordt door de CSP geweigerd zodra deze pagina via een link
4// BINNEN de site binnenkomt (shaer-0i6). Wat de server meegeeft komt uit
5// pageData(); interpolatie kan niet in een statisch bestand.
6
7import { pageData } from './lib.js';
8
9// De twee gedelegeerde blokken dragen een window-vlag en zijn bij een tweede
10// init een no-op; de twee SCANNERS (gif-video's, lees-meer) moeten juist wel
11// elke render opnieuw over de verse elementen lopen (shaer-5s1). Element-
12// vlaggen (data-gif-wired, data-rm) houden dubbel bedraden tegen.
13export function init() { run(); }
14
15function run() {
16
17 (function () {
18 if (window.__tlPasteWired) return; window.__tlPasteWired = true;
19 function modal() { return document.getElementById('tl-paste'); }
20 function openM() {
21 var m = modal(); if (!m) return;
22 var inp = m.querySelector('.tl-paste-input');
23 m.classList.add('is-open');
24 if (inp) {
25 inp.value = ''; inp.focus();
26 if (navigator.clipboard && navigator.clipboard.readText) {
27 navigator.clipboard.readText().then(function (t) {
28 t = (t || '').trim();
29 if (/^https?:\/\//i.test(t) && !inp.value) { inp.value = t; inp.select(); }
30 }).catch(function () {});
31 }
32 }
33 }
34 function closeM() { var m = modal(); if (m) m.classList.remove('is-open'); }
35 function go() {
36 var m = modal(); if (!m) return;
37 var inp = m.querySelector('.tl-paste-input'), v = (inp ? inp.value : '').trim();
38 if (!/^https?:\/\//i.test(v)) { if (inp) inp.focus(); return; }
39 location.href = '/authorize_interaction?uri=' + encodeURIComponent(v);
40 }
41 document.addEventListener('click', function (e) {
42 if (e.target.closest && e.target.closest('#tl-paste-btn')) { e.preventDefault(); openM(); return; }
43 if (e.target.closest && e.target.closest('.tl-paste-go')) { e.preventDefault(); go(); return; }
44 if (e.target.closest && (e.target.closest('.tl-paste-cancel') || e.target.closest('.tl-paste-x'))) { e.preventDefault(); closeM(); return; }
45 var op = document.querySelector('.tl-paste.is-open'); if (op && e.target === op) closeM();
46 });
47 document.addEventListener('keydown', function (e) {
48 var m = document.querySelector('.tl-paste.is-open'); if (!m) return;
49 if (e.key === 'Escape') closeM();
50 else if (e.key === 'Enter' && e.target.closest && e.target.closest('.tl-paste')) { e.preventDefault(); go(); }
51 });
52 })();
53
54
55// ── volgend blok ──
56
57(function(){
58 if (window.__fediRemoteWired) return; window.__fediRemoteWired = true;
59 var current = null, currentBtn = null;
60 function close(){ if (current) { current.remove(); current = null; currentBtn = null; } }
61 function go(raw, uri){ var d=(raw||'').trim().replace(/^@?[^@\s]*@/,'').replace(/^https?:\/\//i,'').replace(/\/.*$/,'').trim(); if(d){ try{ localStorage.setItem('pcmsFediServer', d); }catch(e){} location.href='https://'+d+'/authorize_interaction?uri='+encodeURIComponent(uri||''); } }
62 function place(f, b){ var r=b.getBoundingClientRect(); f.style.top=(r.bottom+window.scrollY+6)+'px'; f.style.left=Math.max(8, Math.min(r.left+window.scrollX, window.scrollX+window.innerWidth-340))+'px'; }
63 document.addEventListener('click', function(e){
64 if (e.target.closest && e.target.closest('.fedi-remote-cancel')) { close(); return; }
65 if (current && e.target.closest && e.target.closest('.fedi-remote-form')) return;
66 var b = e.target.closest && e.target.closest('.fedi-remote-reply-btn');
67 if (b) {
68 e.preventDefault();
69 if (currentBtn === b) { close(); return; }
70 close();
71 var f = document.createElement('form'); f.className='fedi-remote-form'; f.dataset.uri = b.getAttribute('data-fedi-uri')||'';
72 f.innerHTML = '<input type="text" autocomplete="off" spellcheck="false"><button type="submit" class="btn btn-primary fedi-remote-go" aria-label="ok">&rarr;</button><button type="button" class="fedi-remote-cancel" aria-label="x">&times;</button>';
73 var _inp = f.querySelector('input'); _inp.placeholder = b.getAttribute('data-fedi-ph') || 'mastodon.social';
74 try{ var _sv = localStorage.getItem('pcmsFediServer'); if(_sv) _inp.value = _sv; }catch(e){}
75 document.body.appendChild(f); place(f, b); current=f; currentBtn=b; _inp.focus(); _inp.select();
76 return;
77 }
78 if (current) close();
79 });
80 document.addEventListener('submit', function(e){ var f=e.target.closest && e.target.closest('.fedi-remote-form'); if(!f) return; e.preventDefault(); go(f.querySelector('input').value, f.dataset.uri); });
81 document.addEventListener('keydown', function(e){ if (e.key === 'Escape') close(); });
82 window.addEventListener('scroll', close, true);
83})();
84
85/* Short feed videos (gif/cover loops like an animated cover) autoplay + loop muted like a GIF;
86 longer real videos keep their controls. Decided on the actual duration once metadata loads. */
87wireGifVideos();
88
89/* Like/Boost toggle in place — POST via fetch, flip the button, stay on the page (no reload, no banner). */
90(function(){
91 if (window.__newsReactWired) return; window.__newsReactWired = true;
92 document.addEventListener('submit', function(e){
93 var f = e.target.closest && e.target.closest('.tl-react-form');
94 if (!f) return;
95 e.preventDefault();
96 var btn = f.querySelector('button'); if (!btn || btn.disabled) return;
97 btn.disabled = true;
98 var body = new URLSearchParams();
99 new FormData(f).forEach(function(v, k){ body.append(k, v); });
100 fetch(f.action, { method: 'POST', body: body, headers: { 'X-Requested-With': 'fetch' }, credentials: 'same-origin' })
101 .then(function(r){ return r.ok ? r.json() : null; })
102 .then(function(j){ if (j) btn.classList.toggle('is-on', !!j.on); })
103 .catch(function(){})
104 .then(function(){ btn.disabled = false; });
105 });
106})();
107
108// ── volgend blok ──
109
110// Collapse long post bodies to a max height with a "read more" toggle — only when the content
111// actually overflows. Runs on every /news render (full load + htmx swap); a per-element flag
112// prevents double-wiring.
113wireReadMore();
114}
115
116/* Short feed videos: zie de opmerking bij de aanroep in run(). */
117function wireGifVideos(){
118 document.querySelectorAll('.tl-media-video').forEach(function(v){
119 if (v.dataset.gifWired) return; v.dataset.gifWired = '1';
120 var decide = function(){
121 if (v.duration && v.duration <= 30) {
122 v.removeAttribute('controls'); v.loop = true; v.muted = true; v.play().catch(function(){});
123 }
124 };
125 if (v.readyState >= 1) decide(); else v.addEventListener('loadedmetadata', decide, { once: true });
126 });
127}
128
129function wireReadMore(){
130 var _d = pageData(); var RM = _d.readMore || 'Lees meer', SL = _d.showLess || 'Toon minder';
131 document.querySelectorAll('.tl-content:not(.nsfw-media):not([data-rm])').forEach(function(c){
132 c.setAttribute('data-rm', '1');
133 if (c.scrollHeight > 360) {
134 c.classList.add('tl-clamp');
135 var b = document.createElement('button');
136 b.type = 'button'; b.className = 'tl-readmore'; b.textContent = RM;
137 b.addEventListener('click', function(){
138 b.textContent = c.classList.toggle('tl-clamp') ? RM : SL;
139 });
140 c.insertAdjacentElement('afterend', b);
141 }
142 });
143}
144
145// Paginering: items die de feed later binnenhaalt zouden de scanners missen --
146// init() draait per NAVIGATIE, en een pagineer-swap is er geen. Een keer,
147// gedelegeerd; op andere pagina's vinden de scanners niets en doen ze niets.
148document.body.addEventListener('htmx:afterSettle', function () { wireGifVideos(); wireReadMore(); });
Note: See TracBrowser for help on using the repository browser.