| 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 |
|
|---|
| 7 | import { 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.
|
|---|
| 13 | export function init() { run(); }
|
|---|
| 14 |
|
|---|
| 15 | function 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">→</button><button type="button" class="fedi-remote-cancel" aria-label="x">×</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. */
|
|---|
| 87 | wireGifVideos();
|
|---|
| 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.
|
|---|
| 113 | wireReadMore();
|
|---|
| 114 | }
|
|---|
| 115 |
|
|---|
| 116 | /* Short feed videos: zie de opmerking bij de aanroep in run(). */
|
|---|
| 117 | function 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 |
|
|---|
| 129 | function 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.
|
|---|
| 148 | document.body.addEventListener('htmx:afterSettle', function () { wireGifVideos(); wireReadMore(); });
|
|---|