source: Klonkt/src/assets/js/mod/admin-playlists.js@ 4b5db37

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

Modules herstarten per paginawissel: de editor leeft weer na een terugkeer (shaer-5s1)

Drie klachten, een wortel. De oude inline scripts draaiden bij ELKE render;
een ES-module draait zijn top-level EEN keer per sessie, en de bootstrap
importeert een geladen module nooit opnieuw. Dus:

  • /posts/new na een htmx-terugkeer: geen toolbar, geen serialisatie -- het verborgen veld kreeg de chips nooit terug (shortcodes 'opgegeten')
  • /admin/audio na een terugkeer: de eigen kopieerhandler dood, en de klik viel door naar de GEDELEGEERDE handler van admin-media, die voor mediapaden terecht location.origin voorplakt -- vandaar https://site[[track:uuid]] op het klembord

De afspraak is nu: een module die per render moet draaien exporteert init(),
en de bootstrap roept die aan bij elke wissel waarop de module actief is.
Modules zonder init houden hun oude gedrag. Listeners op document/window
overleven de swap met closures naar dode elementen; makeSweeper in lib.js
veegt bij elke init de vorige lichting weg. Gedelegeerde handlers die
bewust blijven leven (media/videos) krijgen een paginawacht, want data-copy
betekent daar een PAD en elders een shortcode.

Omgezet: post-edit, admin-audio, admin-playlists. Bewaakt: admin-media,
admin-videos. playlist-editor en track-editor waren al swap-bestendig
(globale functie, gedelegeerd met eigen guards).

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

  • Property mode set to 100644
File size: 2.8 KB
Line 
1// Afspeellijsten in beheer -- verplaatst uit inline script, shaer-bqr.
2//
3// Servergegevens (het csrf-token en drie teksten) komen uit pageData();
4// interpolatie kan niet in een statisch bestand.
5
6import { pageData } from './lib.js';
7
8// Element-bedrading per render, dus init() per paginawissel (shaer-5s1).
9export function init() { run(); }
10
11function run() {
12(function() {
13 const _d = pageData();
14 const csrf = _d.csrf || '';
15
16 document.getElementById('pl-new-btn')?.addEventListener('click', () => {
17 if (typeof window.openPlaylistEditor === 'function') {
18 window.openPlaylistEditor({ mode: 'create', onSaved: () => location.reload() });
19 }
20 });
21
22 // Click-to-copy on shortcodes
23 document.querySelectorAll('[data-copy]').forEach(el => {
24 el.addEventListener('click', async () => {
25 try {
26 await navigator.clipboard.writeText(el.dataset.copy);
27 el.classList.add('is-copied');
28 const original = el.textContent;
29 el.textContent = '✓ ' + (_d.copied || '');
30 setTimeout(() => { el.classList.remove('is-copied'); el.textContent = original; }, 1200);
31 } catch (_) { /* fall back to selection */ }
32 });
33 });
34
35 document.querySelectorAll('[data-pl-edit]').forEach(btn => {
36 btn.addEventListener('click', () => {
37 if (typeof window.openPlaylistEditor === 'function') {
38 window.openPlaylistEditor({ mode: 'edit', id: btn.dataset.id, onSaved: () => location.reload() });
39 }
40 });
41 });
42
43 document.querySelectorAll('[data-pl-delete]').forEach(btn => {
44 btn.addEventListener('click', async () => {
45 const id = btn.dataset.id;
46 const title = btn.dataset.title || id;
47 if (!confirm((_d.delConfirm || '').replace('{title}', title))) return;
48 try {
49 const r = await fetch(`/admin/playlists/api/${encodeURIComponent(id)}/delete`, {
50 method: 'POST',
51 headers: { 'X-CSRF-Token': csrf },
52 credentials: 'same-origin',
53 });
54 const j = await r.json();
55 if (j.ok) location.reload();
56 else alert((_d.delFailed || '') + ': ' + (j.error || ''));
57 } catch (err) {
58 alert((_d.delFailed || '') + ': ' + err.message);
59 }
60 });
61 });
62
63 // P52 — deep-link from playlist embed (?edit=<id>) auto-opens the editor.
64 // openPlaylistEditor is defined synchronously by the included partial, so
65 // it's available by the time this IIFE runs.
66 (function deepLinkEdit() {
67 const params = new URLSearchParams(location.search);
68 const editId = params.get('edit');
69 if (!editId) return;
70 if (typeof window.openPlaylistEditor !== 'function') return;
71 // Strip the query param immediately so reload after save doesn't re-open.
72 history.replaceState({}, '', location.pathname);
73 window.openPlaylistEditor({
74 mode: 'edit',
75 id: editId,
76 onSaved: () => location.reload(),
77 });
78 })();
79})();
80}
Note: See TracBrowser for help on using the repository browser.