MediaWiki:Minerva.js: Unterschied zwischen den Versionen

Keine Bearbeitungszusammenfassung
Markierung: Zurückgesetzt
Keine Bearbeitungszusammenfassung
Markierung: Manuelle Zurücksetzung
Zeile 6: Zeile 6:


   // --- KONFIG: Label + Seitentitel (werden mit mw.util.getUrl() sicher verlinkt)
   // --- KONFIG: Label + Seitentitel (werden mit mw.util.getUrl() sicher verlinkt)
const LINKS = [
  const LINKS = [
  ['Hauptkategorien', null],
    ['Hauptkategorien', null], // Header/Toggle, kein Link
  ['Alle A Dream of Scotland Abfüllungen', 'Kategorie:Alle A Dream of Scotland Abfüllungen'],
    ['Alle A Dream of Scotland Abfüllungen', 'Kategorie:Alle A Dream of Scotland Abfüllungen'],
  ['Alle A Dream of Ireland Abfüllungen',  'Kategorie:Alle A Dream of Ireland Abfüllungen'],
    ['Alle A Dream of Ireland Abfüllungen',  'Kategorie:Alle A Dream of Ireland Abfüllungen'],
  ['Alle A Dream of... – Der Rest der Welt', 'Kategorie:Alle A Dream of... – Der Rest der Welt Abfüllungen'],
    ['Alle A Dream of... – Der Rest der Welt', 'Kategorie:Alle A Dream of... – Der Rest der Welt Abfüllungen'],
  ['Cigar Malt Übersicht', 'Kategorie:Cigar Malt Übersicht'],
    ['Cigar Malt Übersicht', 'Kategorie:Cigar Malt Übersicht'],
  ['Alle Rumbastic Abfüllungen', 'Kategorie:Alle Rumbastic Abfüllungen'],
    ['Alle Rumbastic Abfüllungen', 'Kategorie:Alle Rumbastic Abfüllungen'],
  ['The Tasteful 8', 'Kategorie:The Tasteful 8'],
    ['The Tasteful 8', 'Kategorie:The Tasteful 8'],
  ['Còmhlan Abfüllungen', 'Kategorie:Còmhlan Abfüllungen'],
    ['Còmhlan Abfüllungen', 'Kategorie:Còmhlan Abfüllungen'],
  ['Friendly Mr. Z Whiskytainment Abfüllungen', 'Kategorie:Friendly Mr. Z Whiskytainment Abfüllungen'],
    ['Friendly Mr. Z Whiskytainment Abfüllungen', 'Kategorie:Friendly Mr. Z Whiskytainment Abfüllungen'],
  ['Die Whisky Elfen Abfüllungen', 'Kategorie:Die Whisky Elfen Abfüllungen'],
    ['Die Whisky Elfen Abfüllungen', 'Kategorie:Die Whisky Elfen Abfüllungen'],
  ['The Fine Art of Whisky Abfüllungen', 'Kategorie:The Fine Art of Whisky Abfüllungen'],
    ['The Fine Art of Whisky Abfüllungen', 'Kategorie:The Fine Art of Whisky Abfüllungen'],
  ['The Forbidden Kingdom', 'Kategorie:The Forbidden Kingdom'],
    ['The Forbidden Kingdom', 'Kategorie:The Forbidden Kingdom'],
  ['Sonderabfüllungen', 'Kategorie:Sonderabfüllungen'],
    ['Sonderabfüllungen', 'Kategorie:Sonderabfüllungen'] // <— NEU
 
   ];
  // --- NEUER REITER / SEKTION ---
   ['📊 Diagramm / Statistik', null],
  ['Abfüllungen pro Jahr', 'Abfüllungen_pro_Jahr'],
  // optional später:
  // ['Top 5 – Community', 'Top_5'],
];


   const BLOCK_ID = 'ados-custom-links';
   const BLOCK_ID = 'ados-custom-links';
Zeile 40: Zeile 34:
   }
   }


function build() {
  function build() {
  const host = findMenuList();
    const host = findMenuList();
  if (!host) return false;
    if (!host) return false;
 
    if (document.getElementById(BLOCK_ID)) return true; // schon eingebaut
  // Block schon eingebaut?
  if (document.getElementById(BLOCK_ID)) return true;
 
  // Container für alle Sektionen
  const container = document.createElement('div');
  container.id = BLOCK_ID;
 
  // LINKS in Sektionen aufteilen: jeder Header (title=null) startet neue Sektion
  const sections = [];
  let current = null;
 
  for (const [label, title] of LINKS) {
    if (title === null) {
      current = { header: label, items: [] };
      sections.push(current);
    } else if (current) {
      current.items.push({ label, title });
    }
  }
 
  // Sektionen bauen
  sections.forEach((sec, idx) => {
    const secId = `${BLOCK_ID}-sec-${idx}`;


    // äußerer Block
     const outer = document.createElement('ul');
     const outer = document.createElement('ul');
    outer.id = BLOCK_ID;
     outer.className = 'toggle-list__list';
     outer.className = 'toggle-list__list';


     // Header
     // Header mit Icon + Toggle
    const [headerLabel] = LINKS[0];
     const headerLi = document.createElement('li');
     const headerLi = document.createElement('li');
     headerLi.className = 'toggle-list-item';
     headerLi.className = 'toggle-list-item';
Zeile 81: Zeile 55:
     headerBtn.innerHTML =
     headerBtn.innerHTML =
       '<span class="minerva-icon minerva-icon--listBullet"></span>' +
       '<span class="minerva-icon minerva-icon--listBullet"></span>' +
       `<span class="toggle-list-item__label">${sec.header}</span>`;
       `<span class="toggle-list-item__label">${headerLabel}</span>`;


     headerLi.appendChild(headerBtn);
     headerLi.appendChild(headerBtn);
     outer.appendChild(headerLi);
     outer.appendChild(headerLi);


     // Inner list
     // Unterpunkte-Liste (ohne Icons)
     const inner = document.createElement('ul');
     const inner = document.createElement('ul');
     inner.className = 'toggle-list__list';
     inner.className = 'toggle-list__list';
     inner.style.marginLeft = '10px';
     inner.style.marginLeft = '10px';


     sec.items.forEach(({ label, title }) => {
     for (let i = 1; i < LINKS.length; i++) {
      const [label, title] = LINKS[i];
       const li = document.createElement('li');
       const li = document.createElement('li');
       li.className = 'toggle-list-item';
       li.className = 'toggle-list-item';
Zeile 98: Zeile 73:
       a.className = 'toggle-list-item__anchor';
       a.className = 'toggle-list-item__anchor';
       a.textContent = label;
       a.textContent = label;
       a.href = mw.util.getUrl(title);
       a.href = title ? mw.util.getUrl(title) : '#';


      // KEIN Icon bei Unterpunkten
       li.appendChild(a);
       li.appendChild(a);
       inner.appendChild(li);
       inner.appendChild(li);
     });
     }
 
     outer.appendChild(inner);
     outer.appendChild(inner);


     // Toggle-Logik pro Sektion
     // Toggle-Logik
     headerBtn.addEventListener('click', function () {
     headerBtn.addEventListener('click', function () {
       const expanded = this.getAttribute('aria-expanded') === 'true';
       const expanded = this.getAttribute('aria-expanded') === 'true';
       this.setAttribute('aria-expanded', String(!expanded));
       this.setAttribute('aria-expanded', String(!expanded));
       inner.style.display = expanded ? 'none' : '';
       inner.style.display = expanded ? 'none' : '';
       try { localStorage.setItem(secId + ':collapsed', expanded ? '1' : '0'); } catch (e) {}
       try { localStorage.setItem(BLOCK_ID + ':collapsed', expanded ? '1' : '0'); } catch (e) {}
     });
     });


     // Zustand wiederherstellen
     // Zustand wiederherstellen
     try {
     try {
       if (localStorage.getItem(secId + ':collapsed') === '1') {
       if (localStorage.getItem(BLOCK_ID + ':collapsed') === '1') {
         headerBtn.setAttribute('aria-expanded', 'false');
         headerBtn.setAttribute('aria-expanded', 'false');
         inner.style.display = 'none';
         inner.style.display = 'none';
Zeile 122: Zeile 97:
     } catch (e) {}
     } catch (e) {}


     container.appendChild(outer);
     // nach der ersten vorhandenen UL einfügen (direkt unter Start/Zufällige Seite)
  });
    const firstUl = host.querySelector('ul') || host;
    (firstUl.parentNode || host).insertBefore(outer, firstUl.nextSibling);


  // Einfügen (wie bei dir: direkt nach erster UL)
    return true;
  const firstUl = host.querySelector('ul') || host;
   }
   (firstUl.parentNode || host).insertBefore(container, firstUl.nextSibling);


   return true;
   // beim Laden probieren …
}
  document.addEventListener('DOMContentLoaded', () => setTimeout(build, 0));
  // … und wenn das Burger-Menü dynamisch aufgebaut wird, nochmal
  document.addEventListener('click', (e) => {
    const btn = e.target.closest('button, a');
    if (!btn) return;
    const s = (btn.className + ' ' + btn.id).toLowerCase();
    if (s.includes('menu') || s.includes('hamburger') || s.includes('main-menu')) {
      setTimeout(build, 250);
    }
  });
  // Fallback: Observer für lazy DOM
  const obs = new MutationObserver(() => { if (build()) obs.disconnect(); });
  obs.observe(document.documentElement, { childList: true, subtree: true });
})();