/* * Kategorien und Schlagwörter eines Beitrags: das Textfeld mit der Liste durch Komma bleibt, was * gespeichert wird. Darunter stehen die vorhandenen Namen zum Anklicken - ein Klick nimmt einen * Namen auf oder heraus. Neue Namen tippt man weiter ein. * * Über den Dokumentknoten, weil die Suche in der Inhaltsliste die Ergebnisse austauscht. */ const split = value => value.split(',').map(name => name.trim()).filter(Boolean); const same = (a, b) => a.localeCompare(b, 'de', { sensitivity: 'base' }) === 0; const enhance = input => { if (input.dataset.termReady) return; let names = []; try { names = JSON.parse(input.dataset.termInput || '[]'); } catch { names = []; } input.dataset.termReady = '1'; if (!names.length) return; const box = document.createElement('div'); box.className = 'term-chips'; box.setAttribute('role', 'group'); const label = document.querySelector(`label[for="${input.id}"]`)?.textContent || 'Vorhandene Namen'; box.setAttribute('aria-label', `${label}: vorhandene zum Übernehmen`); const sync = () => { const chosen = split(input.value); for (const chip of box.children) chip.setAttribute('aria-pressed', String(chosen.some(name => same(name, chip.dataset.name)))); }; for (const name of names) { const chip = document.createElement('button'); chip.type = 'button'; chip.className = 'term-chip'; chip.dataset.name = name; chip.textContent = name; chip.addEventListener('click', () => { const chosen = split(input.value); const next = chosen.some(entry => same(entry, name)) ? chosen.filter(entry => !same(entry, name)) : [...chosen, name]; input.value = next.join(', '); input.dispatchEvent(new Event('input', { bubbles: true })); sync(); }); box.append(chip); } input.addEventListener('input', sync); const help = input.parentElement.querySelector('.field-help'); (help ?? input).after(box); sync(); }; const all = () => document.querySelectorAll('[data-term-input]').forEach(enhance); all(); new MutationObserver(all).observe(document.body, { childList: true, subtree: true });