MediaWiki:Common.js: Unterschied zwischen den Versionen

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




function setupWidget(box) {
/* Whisky-Ratings – eigenes Frontend für RatePage (Variante B) */
  const pageId  = mw.config.get('wgArticleId');
mw.loader.using(['mediawiki.api', 'mediawiki.user']).then(function () {
  const contest  = box.dataset.ratepageContest || undefined;
  const scale    = parseInt(box.dataset.ratepageScale || '10', 10);


   const widget = box.querySelector('.whisky-rating__widget');
   function init() {
  const meta  = box.querySelector('.whisky-rating__meta');
    document.querySelectorAll('.whisky-rating__item').forEach(setupWidget);
  }


   const isAnon = mw.user.isAnon();
   function setupWidget(box) {
   if (isAnon) {
    const pageTitle = box.dataset.ratepageTitle;
    box.classList.add('whisky-rating--disabled');
    const contest   = box.dataset.ratepageContest || undefined;
     meta.textContent = 'Bitte einloggen, um zu bewerten.';
     const scale    = parseInt(box.dataset.ratepageScale || '10', 10);
  }


  // --- Gläser rendern ---
     const widget = box.querySelector('.whisky-rating__widget');
  const buttons = [];
     const meta  = box.querySelector('.whisky-rating__meta');
  for (let i = 1; i <= scale; i++) {
     const btn = document.createElement('button');
    btn.type = 'button';
    btn.className = 'whisky-glass';
     btn.setAttribute('aria-label', i + ' von ' + scale);
    btn.setAttribute('aria-pressed', 'false');


    const isAnon = mw.user.isAnon();
     if (isAnon) {
     if (isAnon) {
       btn.disabled = true;
       box.classList.add('whisky-rating--disabled');
      btn.title = 'Nur für registrierte Benutzer';
       meta.textContent = 'Bitte einloggen, um zu bewerten.';
    } else {
      btn.title = i + ' / ' + scale;
      btn.addEventListener('mouseenter', () => highlight(i));
      btn.addEventListener('mouseleave', () => highlight(current));
       btn.addEventListener('click', () => vote(i));
      btn.addEventListener('keydown', (e) => {
        if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); vote(i); }
        if (e.key === 'ArrowRight' && i < scale) buttons[i].focus();
        if (e.key === 'ArrowLeft'  && i > 1)    buttons[i-2].focus();
      });
     }
     }
    widget.appendChild(btn);
    buttons.push(btn);
  }


  let current = 0;
    // Buttons bauen
  highlight(current);
    const buttons = [];
    for (let i = 1; i <= scale; i++) {
      const btn = document.createElement('button');
      btn.type = 'button';
      btn.className = 'whisky-glass';
      btn.setAttribute('aria-label', i + ' von ' + scale);
      btn.setAttribute('aria-pressed', 'false');


  function highlight(n) {
      if (isAnon) {
    buttons.forEach((b, idx) => {
        btn.disabled = true;
      const active = (idx < n);
        btn.title = 'Nur für registrierte Benutzer';
      b.classList.toggle('is-active', active);
      } else {
      b.setAttribute('aria-pressed', active ? 'true' : 'false');
        btn.title = i + ' / ' + scale;
     });
        btn.addEventListener('mouseenter', () => highlight(i));
  }
        btn.addEventListener('mouseleave', () => highlight(current));
        btn.addEventListener('click', () => vote(i));
        btn.addEventListener('keydown', (e) => {
          if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); vote(i); }
          if (e.key === 'ArrowRight' && i < scale) buttons[i].focus();
          if (e.key === 'ArrowLeft'  && i > 1)     buttons[i-2].focus();
        });
      }
      widget.appendChild(btn);
      buttons.push(btn);
    }


  // --- NEU: Stats laden & anzeigen ---
     let current = 0;
  function updateStats() {
     highlight(current);
     const api = new mw.Api();
     api.get({
      action: 'query',
      prop: 'pagerating',
      pageids: pageId,
      prcontest: contest || undefined,
      format: 'json'
    }).done(function (data) {
      try {
        const page = data.query.pages[pageId];
        const pr = page.pagerating;
        if (!pr) { meta.textContent = ''; return; }


         // Darf Ergebnisse sehen?
    function highlight(n) {
         if (typeof pr.canSee !== 'undefined' && pr.canSee === 0) {
      buttons.forEach((b, idx) => {
          meta.textContent = 'Bewertungen sind verborgen.';
         const active = (idx < n);
          return;
         b.classList.toggle('is-active', active);
        }
        b.setAttribute('aria-pressed', active ? 'true' : 'false');
      });
    }
 
    function vote(value) {
      const api = new mw.Api();


        // Histogramm -> Ø und Count
      meta.textContent = 'Wird gespeichert …';
        const hist = pr.pageRating || {};
        let total = 0, sum = 0;
        Object.keys(hist).forEach(k => {
          const score = parseInt(k, 10);
          const cnt = parseInt(hist[k], 10);
          if (!isNaN(score) && !isNaN(cnt)) {
            total += cnt;
            sum += score * cnt;
          }
        });
        if (total > 0) {
          const avg = Math.round((sum / total) * 10) / 10; // 1 Nachkommastelle
          meta.textContent = `Ø ${avg} (${total} Stimmen)`;
        } else {
          meta.textContent = 'Noch keine Bewertungen';
        }


         // Eigene Stimme (falls vorhanden) markieren
      api.postWithToken('csrf', {
         if (pr.userVote) {
        action: 'ratepage',
          current = pr.userVote;
        pagetitle: pageTitle, // Seitentitel, z. B. "Lagavulin 16"
          highlight(current);
        answer: value,        // 1..10
         }
         contest: contest,    // "NASE" | "GESCHMACK" | "ABGANG"
      } catch (e) {
         format: 'json'
         console.error(e);
      }).done(function (data) {
       }
        current = value;
    }).fail(function (xhr) {
        highlight(current);
      console.error('Pagerating-Load-Error', xhr);
         meta.textContent = 'Danke! Deine Bewertung: ' + value + ' / ' + scale;
     });
        // Tipp: Wenn du später Durchschnitt/Anzahl anzeigen willst,
        // kannst du hier einen zusätzlichen API-Call einbauen,
         // sofern du die Stats von RatePage abrufen möchtest.
       }).fail(function (err) {
        console.error(err);
        meta.textContent = 'Speichern fehlgeschlagen. Bitte später erneut versuchen.';
      });
     }
   }
   }


   // --- Voting bleibt wie gehabt, zusätzlich Stats aktualisieren ---
   // Warten bis der DOM da ist (auch bei VisualEditor-Nachladungen)
   function vote(value) {
   if (document.readyState === 'loading') {
    const api = new mw.Api();
    document.addEventListener('DOMContentLoaded', init);
    meta.textContent = 'Wird gespeichert …';
  } else {
 
    init();
    api.postWithToken('csrf', {
      action: 'ratepage',
      pageid: pageId,              // stabiler als pagetitle
      answer: value,
      contest: contest || undefined,
      format: 'json'
    }).done(function () {
      current = value;
      highlight(current);
      // Nach Speichern frische Zahlen laden:
      updateStats();
    }).fail(function (xhr) {
      let msg = 'Unbekannter Fehler';
      try {
        const j = xhr && xhr.responseJSON ? xhr.responseJSON : xhr;
        if (j && j.error) {
          msg = (j.error.code ? j.error.code + ': ' : '') + (j.error.info || '');
        }
      } catch(e){}
      console.error('RatePage-API-Fehler:', xhr);
      meta.textContent = 'Speichern fehlgeschlagen: ' + msg;
    });
   }
   }
 
});
  // Initial die Stats holen
  updateStats();
}