source: Klonkt/src/assets/js/mod/admin-seo.js@ 3188dfe

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

Kandidaten als kaartje, regel voor regel (shaer-mbz)

Een keuze en geen opsomming. Alles op een rij duwen maakte de toelichting --
juist het veld dat twee gelijknamige bands uit elkaar houdt -- tot bijzin achter
de naam. Nu: naam, toelichting, feiten, en een voet met de link en de knop.

Alleen wat er IS. Een lege bullet tussen twee punten leest als ontbrekende
informatie in plaats van als afwezige, dus soort, land en jaren worden pas
samengevoegd nadat de lege eruit zijn.

De zoekscore komt er alleen bij als hij ZWAK is (< 70). Bij een goede treffer is
een getal ruis; bij een zwakke is het een waarschuwing. Dat veld haalden we al
op met precies die bedoeling en het werd nog nergens gebruikt.

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

  • Property mode set to 100644
File size: 6.1 KB
Line 
1// De SEO-pagina: op dit moment alleen het MusicBrainz-paneel (shaer-mbz).
2//
3// De rest van dit scherm is gewone formuliervelden en heeft geen JavaScript
4// nodig; deze module bestaat omdat opzoeken dat wel doet.
5
6import { pageData, makeSweeper } from './lib.js';
7
8const doc = makeSweeper();
9let T = {};
10
11export function init() {
12 doc.sweep();
13 T = pageData();
14 run();
15}
16
17function run() {
18 // Binnen run() en niet op moduleniveau: deze modules krijgen bij elke
19 // paginawissel opnieuw init(), en een blok dat maar een keer per sessie
20 // draait is precies wat shaer-5s1 opleverde.
21 wireMusicBrainz();
22}
23
24/**
25 * "Zoek jezelf op" in MusicBrainz.
26 *
27 * De kandidaten komen van de server, want MusicBrainz eist een verzoek per
28 * seconde per APPLICATIE en een User-Agent met contact -- allebei niet vanuit
29 * een browser af te dwingen.
30 *
31 * WIJ KIEZEN NIET. Ook niet als er precies een treffer is: een verkeerd geraden
32 * MBID zet jouw naam onder andermans werk. De knop staat er, de klik is van de
33 * artiest. En de keuze gaat mee met de Opslaan van de pagina -- een eigen
34 * formulier kan hier niet, want deze pagina IS er een.
35 */
36function wireMusicBrainz() {
37 const knop = document.getElementById('mb-zoek-btn');
38 const veld = document.getElementById('mb-q');
39 const uit = document.getElementById('mb-uit');
40 const idVeld = document.getElementById('mb-id');
41 const naamVeld = document.getElementById('mb-naam');
42 const huidig = document.getElementById('mb-huidig');
43 if (!knop || !veld || !uit || !idVeld || knop.__wired) return;
44 knop.__wired = true;
45
46 const el = (tag, cls, tekst) => {
47 const e = document.createElement(tag);
48 if (cls) e.className = cls;
49 // textContent en nooit innerHTML: dit is tekst uit een vreemd register.
50 if (tekst != null) e.textContent = tekst;
51 return e;
52 };
53
54 function zet(mbid, naam) {
55 idVeld.value = mbid || '';
56 if (naamVeld) naamVeld.value = naam || '';
57 if (huidig) {
58 huidig.hidden = !mbid;
59 const n = document.getElementById('mb-huidig-naam');
60 const a = document.getElementById('mb-huidig-link');
61 if (n) n.textContent = naam || mbid || '';
62 if (a) a.href = mbid ? `https://musicbrainz.org/artist/${mbid}` : '#';
63 }
64 uit.hidden = true;
65 uit.replaceChildren();
66 checkTerugweg(mbid);
67 }
68
69 const wis = document.getElementById('mb-wis');
70 if (wis) wis.addEventListener('click', () => zet('', ''));
71
72 // DE TERUG-WEG. Wij zetten hem niet -- dat kan niet via hun API en hoort ook
73 // niet -- we kijken alleen of de artiestenpagina ons domein noemt. Zolang dat
74 // niet zo is staat er "nog eenzijdig", want een halve koppeling die als
75 // bevestigd leest is het soort stilte waar we vandaag al genoeg van zagen.
76 const terugweg = document.getElementById('mb-terugweg');
77 async function checkTerugweg(mbid) {
78 if (!terugweg) return;
79 if (!mbid) { terugweg.hidden = true; terugweg.textContent = ''; return; }
80 terugweg.hidden = false;
81 terugweg.className = 'mb-terugweg';
82 terugweg.textContent = T.mb_checking || 'Terug-weg controleren…';
83 try {
84 const r = await fetch(`/admin/seo/api/musicbrainz/terugweg?mbid=${encodeURIComponent(mbid)}`, { credentials: 'same-origin' });
85 const j = await r.json();
86 terugweg.className = 'mb-terugweg ' + (j.verified ? 'is-ok' : 'is-eenzijdig');
87 terugweg.textContent = j.verified
88 ? (T.mb_verified || 'Wederzijds.')
89 : (T.mb_unverified || 'Nog eenzijdig.');
90 } catch {
91 terugweg.hidden = true;
92 }
93 }
94 // Meteen bij het openen, want de artiest kan hem intussen op MusicBrainz
95 // hebben gezet en hoort dat hier te zien zonder opnieuw te koppelen.
96 if (idVeld.value) checkTerugweg(idVeld.value);
97
98 async function zoek() {
99 const q = (veld.value || '').trim();
100 if (!q) return;
101 uit.hidden = false;
102 uit.replaceChildren(el('p', 'form-hint', T.mb_busy || 'Zoeken…'));
103 knop.disabled = true;
104 try {
105 const r = await fetch(`/admin/seo/api/musicbrainz?q=${encodeURIComponent(q)}`, { credentials: 'same-origin' });
106 const j = await r.json();
107 toon((j && j.kandidaten) || []);
108 } catch {
109 uit.replaceChildren(el('p', 'form-hint', T.mb_fail || 'MusicBrainz is even niet bereikbaar.'));
110 } finally {
111 knop.disabled = false;
112 }
113 }
114
115 function toon(kandidaten) {
116 if (!kandidaten.length) {
117 uit.replaceChildren(el('p', 'form-hint', T.mb_none || 'Niets gevonden.'));
118 return;
119 }
120 const lijst = el('ul', 'mb-lijst');
121 for (const k of kandidaten) {
122 const li = el('li', 'mb-kandidaat');
123
124 // Regel voor regel, want dit is een KEUZE en geen opsomming. Alles op een
125 // rij duwen maakt de toelichting -- juist het veld dat de bands uit
126 // elkaar houdt -- tot bijzin achter de naam.
127 li.appendChild(el('span', 'mb-naam', k.naam));
128
129 // De toelichting is het hele punt: er zijn drie bands die Nirvana heten,
130 // en zonder dit veld kiest iemand de verkeerde. Eigen regel dus.
131 if (k.toelichting) li.appendChild(el('span', 'mb-toelichting', k.toelichting));
132
133 // De feiten eronder, en alleen wat er IS. Een lege bullet tussen twee
134 // punten leest als ontbrekende informatie in plaats van als afwezige.
135 const feiten = [k.soort, k.land, k.jaren].filter(Boolean).join(' · ');
136 if (feiten) li.appendChild(el('span', 'mb-feiten', feiten));
137
138 const voet = el('div', 'mb-voet');
139 const open = el('a', 'mb-open', T.mb_open || 'Bekijk op MusicBrainz');
140 open.href = k.url; open.target = '_blank'; open.rel = 'noopener';
141 voet.appendChild(open);
142 // Hun eigen score. Alleen tonen als hij ZWAK is: bij een goede treffer is
143 // een getal ruis, bij een zwakke is het een waarschuwing.
144 if (k.score && k.score < 70) voet.appendChild(el('span', 'mb-zwak', `${k.score}%`));
145 const b = el('button', 'btn mb-kies', T.mb_pick || 'Dit ben ik');
146 b.type = 'button';
147 b.addEventListener('click', () => zet(k.mbid, k.naam));
148 voet.appendChild(b);
149 li.appendChild(voet);
150
151 lijst.appendChild(li);
152 }
153 uit.replaceChildren(lijst);
154 }
155
156 knop.addEventListener('click', zoek);
157 veld.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); zoek(); } });
158}
Note: See TracBrowser for help on using the repository browser.