source: Klonkt/src/assets/js/mod/admin-seo.js@ 013e16c

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

Naar SEO & social, want sameAs is schema.org (Robins vraag)

Hij vroeg of het niet onder SEO en social hoort, "omdat het ook een soort
koppeling is". Dat is het, en sterker dan dat: op die pagina staat een blok
"Uitgever (JSON-LD / rich results)", en sameAs IS een schema.org-eigenschap.
Zelfde vocabulaire, zelfde plek. Het paneel staat nu direct onder Uitgever.

DAARDOOR VOEDT EEN KOPPELING NU TWEE UITGANGEN. Naast schema:sameAs op de
fediverse-actor komt hij in de JSON-LD van de pagina zelf, in _publisher. Dat
is hetzelfde feit, verteld aan de andere lezer -- en het was gratis, want het
blok stond er al.

BETERE LABELS, want de oude waren geschreven voor het audioscherm. "Ben jij dit
in MusicBrainz?" werd "MusicBrainz (dezelfde artiest elders)" als legenda, met
een hint die zegt wat het OPLEVERT in plaats van alleen wat het is: je komt als
sameAs in de JSON-LD en in je fediverse-profiel, en er verandert niets bij
MusicBrainz zelf. Dat laatste is de geruststelling die er hoort te staan. Plus
een veldlabel ("Zoek jezelf op") met de toelichting "de naam waaronder je muziek
uitbrengt" -- want dat is de vraag, niet je sitenaam. Drie talen.

Het zoekveld begint nu op publisher_name en valt terug op de sitetitel: op deze
pagina heb je die naam net ingevuld.

Meeverhuisd: het endpoint (/admin/seo/api/musicbrainz) en het clientblok, in een
nieuwe mod/admin-seo.js. Die pagina had nog geen JavaScript; opzoeken vraagt er
wel om. Het profielscherm is weer helemaal schoon.

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

  • Property mode set to 100644
File size: 4.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 }
67
68 const wis = document.getElementById('mb-wis');
69 if (wis) wis.addEventListener('click', () => zet('', ''));
70
71 async function zoek() {
72 const q = (veld.value || '').trim();
73 if (!q) return;
74 uit.hidden = false;
75 uit.replaceChildren(el('p', 'form-hint', T.aseo_mb_busy || 'Zoeken…'));
76 knop.disabled = true;
77 try {
78 const r = await fetch(`/admin/seo/api/musicbrainz?q=${encodeURIComponent(q)}`, { credentials: 'same-origin' });
79 const j = await r.json();
80 toon((j && j.kandidaten) || []);
81 } catch {
82 uit.replaceChildren(el('p', 'form-hint', T.aseo_mb_fail || 'MusicBrainz is even niet bereikbaar.'));
83 } finally {
84 knop.disabled = false;
85 }
86 }
87
88 function toon(kandidaten) {
89 if (!kandidaten.length) {
90 uit.replaceChildren(el('p', 'form-hint', T.aseo_mb_none || 'Niets gevonden.'));
91 return;
92 }
93 const lijst = el('ul', 'mb-lijst');
94 for (const k of kandidaten) {
95 const li = el('li', 'mb-kandidaat');
96 li.appendChild(el('strong', null, k.naam));
97 // De toelichting is het hele punt: er zijn drie bands die Nirvana heten,
98 // en zonder dit veld kiest iemand de verkeerde.
99 const bij = [k.toelichting, k.soort, k.land, k.jaren].filter(Boolean).join(' · ');
100 if (bij) li.appendChild(el('small', 'mb-bij', bij));
101 const open = el('a', 'mb-open', T.aseo_mb_open || 'Bekijk op MusicBrainz');
102 open.href = k.url; open.target = '_blank'; open.rel = 'noopener';
103 li.appendChild(open);
104 const b = el('button', 'btn', T.aseo_mb_pick || 'Dit ben ik');
105 b.type = 'button';
106 b.addEventListener('click', () => zet(k.mbid, k.naam));
107 li.appendChild(b);
108 lijst.appendChild(li);
109 }
110 uit.replaceChildren(lijst);
111 }
112
113 knop.addEventListener('click', zoek);
114 veld.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); zoek(); } });
115}
Note: See TracBrowser for help on using the repository browser.