source: Klonkt/src/assets/js/mod/news.js@ 52fc278

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

De Krant en de downloadpagina, met het data-kanaal in gebruik (shaer-bqr, stap 3d)

De eerste twee die servergegevens nodig hadden. news gebruikte twee vertalingen,
download een berekende URL.

EEN ONTWERPCORRECTIE die het bouwen opleverde: de gegevens horen gedeclareerd te
worden waar ze BEKEND zijn, niet door de route geregen. fileUrl wordt in de
template zelf berekend, en t() bestaat in een route helemaal niet. Dus geeft de
pagina zijn eigen gegevens mee aan de include:

include('../partials/page-data', { pageData: { fileUrl: fileUrl } })

De route noemt alleen nog de module. Dat scheelt in elke volgende pagina een
omweg langs de route, en het houdt de gegevens naast de plek waar ze vandaan
komen.

Gecontroleerd dat er in GEEN enkele module nog een EJS-tag staat -- dat is de
enige manier om zeker te weten dat er niets stilzwijgend is blijven hangen dat
straks als letterlijke tekst in een statisch bestand belandt.

Templates compileren, suite 565/565.

  • Property mode set to 100644
File size: 6.7 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 (function () {
10 if (window.__tlPasteWired) return; window.__tlPasteWired = true;
11 function modal() { return document.getElementById('tl-paste'); }
12 function openM() {
13 var m = modal(); if (!m) return;
14 var inp = m.querySelector('.tl-paste-input');
15 m.classList.add('is-open');
16 if (inp) {
17 inp.value = ''; inp.focus();
18 if (navigator.clipboard && navigator.clipboard.readText) {
19 navigator.clipboard.readText().then(function (t) {
20 t = (t || '').trim();
21 if (/^https?:\/\//i.test(t) && !inp.value) { inp.value = t; inp.select(); }
22 }).catch(function () {});
23 }
24 }
25 }
26 function closeM() { var m = modal(); if (m) m.classList.remove('is-open'); }
27 function go() {
28 var m = modal(); if (!m) return;
29 var inp = m.querySelector('.tl-paste-input'), v = (inp ? inp.value : '').trim();
30 if (!/^https?:\/\//i.test(v)) { if (inp) inp.focus(); return; }
31 location.href = '/authorize_interaction?uri=' + encodeURIComponent(v);
32 }
33 document.addEventListener('click', function (e) {
34 if (e.target.closest && e.target.closest('#tl-paste-btn')) { e.preventDefault(); openM(); return; }
35 if (e.target.closest && e.target.closest('.tl-paste-go')) { e.preventDefault(); go(); return; }
36 if (e.target.closest && (e.target.closest('.tl-paste-cancel') || e.target.closest('.tl-paste-x'))) { e.preventDefault(); closeM(); return; }
37 var op = document.querySelector('.tl-paste.is-open'); if (op && e.target === op) closeM();
38 });
39 document.addEventListener('keydown', function (e) {
40 var m = document.querySelector('.tl-paste.is-open'); if (!m) return;
41 if (e.key === 'Escape') closeM();
42 else if (e.key === 'Enter' && e.target.closest && e.target.closest('.tl-paste')) { e.preventDefault(); go(); }
43 });
44 })();
45
46
47// ── volgend blok ──
48
49(function(){
50 if (window.__fediRemoteWired) return; window.__fediRemoteWired = true;
51 var current = null, currentBtn = null;
52 function close(){ if (current) { current.remove(); current = null; currentBtn = null; } }
53 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||''); } }
54 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'; }
55 document.addEventListener('click', function(e){
56 if (e.target.closest && e.target.closest('.fedi-remote-cancel')) { close(); return; }
57 if (current && e.target.closest && e.target.closest('.fedi-remote-form')) return;
58 var b = e.target.closest && e.target.closest('.fedi-remote-reply-btn');
59 if (b) {
60 e.preventDefault();
61 if (currentBtn === b) { close(); return; }
62 close();
63 var f = document.createElement('form'); f.className='fedi-remote-form'; f.dataset.uri = b.getAttribute('data-fedi-uri')||'';
64 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>';
65 var _inp = f.querySelector('input'); _inp.placeholder = b.getAttribute('data-fedi-ph') || 'mastodon.social';
66 try{ var _sv = localStorage.getItem('pcmsFediServer'); if(_sv) _inp.value = _sv; }catch(e){}
67 document.body.appendChild(f); place(f, b); current=f; currentBtn=b; _inp.focus(); _inp.select();
68 return;
69 }
70 if (current) close();
71 });
72 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); });
73 document.addEventListener('keydown', function(e){ if (e.key === 'Escape') close(); });
74 window.addEventListener('scroll', close, true);
75})();
76
77/* Short feed videos (gif/cover loops like an animated cover) autoplay + loop muted like a GIF;
78 longer real videos keep their controls. Decided on the actual duration once metadata loads. */
79(function(){
80 document.querySelectorAll('.tl-media-video').forEach(function(v){
81 if (v.dataset.gifWired) return; v.dataset.gifWired = '1';
82 var decide = function(){
83 if (v.duration && v.duration <= 30) {
84 v.removeAttribute('controls'); v.loop = true; v.muted = true; v.play().catch(function(){});
85 }
86 };
87 if (v.readyState >= 1) decide(); else v.addEventListener('loadedmetadata', decide, { once: true });
88 });
89})();
90
91/* Like/Boost toggle in place — POST via fetch, flip the button, stay on the page (no reload, no banner). */
92(function(){
93 if (window.__newsReactWired) return; window.__newsReactWired = true;
94 document.addEventListener('submit', function(e){
95 var f = e.target.closest && e.target.closest('.tl-react-form');
96 if (!f) return;
97 e.preventDefault();
98 var btn = f.querySelector('button'); if (!btn || btn.disabled) return;
99 btn.disabled = true;
100 var body = new URLSearchParams();
101 new FormData(f).forEach(function(v, k){ body.append(k, v); });
102 fetch(f.action, { method: 'POST', body: body, headers: { 'X-Requested-With': 'fetch' }, credentials: 'same-origin' })
103 .then(function(r){ return r.ok ? r.json() : null; })
104 .then(function(j){ if (j) btn.classList.toggle('is-on', !!j.on); })
105 .catch(function(){})
106 .then(function(){ btn.disabled = false; });
107 });
108})();
109
110// ── volgend blok ──
111
112// Collapse long post bodies to a max height with a "read more" toggle — only when the content
113// actually overflows. Runs on every /news render (full load + htmx swap); a per-element flag
114// prevents double-wiring.
115(function(){
116 var _d = pageData(); var RM = _d.readMore || 'Lees meer', SL = _d.showLess || 'Toon minder';
117 document.querySelectorAll('.tl-content:not(.nsfw-media):not([data-rm])').forEach(function(c){
118 c.setAttribute('data-rm', '1');
119 if (c.scrollHeight > 360) {
120 c.classList.add('tl-clamp');
121 var b = document.createElement('button');
122 b.type = 'button'; b.className = 'tl-readmore'; b.textContent = RM;
123 b.addEventListener('click', function(){
124 b.textContent = c.classList.toggle('tl-clamp') ? RM : SL;
125 });
126 c.insertAdjacentElement('afterend', b);
127 }
128 });
129})();
Note: See TracBrowser for help on using the repository browser.