MediaWiki:Common.js: Unterschied zwischen den Versionen

Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
Zeile 599: Zeile 599:
   })(jQuery, mw);
   })(jQuery, mw);
});
});
/* --- Whisky Top-5 auf der Hauptseite ------------------------------------ */
mw.loader.using(['mediawiki.api']).then(function () {
  function get(obj, path) { var c=obj,i; for(i=0;i<path.length;i++){ if(!c||typeof c!=='object') return; c=c[path[i]]; } return c; }
  function parseWeights(raw, contests) {
    var map = {}, parts = (raw||'').split(','), i;
    for (i=0;i<parts.length;i++){
      var kv = parts[i].split(':'); if (kv.length!==2) continue;
      var k = kv[0].replace(/^\s+|\s+$/g,''); var v = parseFloat(kv[1]);
      if (!isNaN(v)) map[k]=v;
    }
    for (i=0;i<contests.length;i++){ if (typeof map[contests[i]]!=='number') map[contests[i]]=1; }
    return map;
  }
  function fetchCategoryMembers(cat, limit) {
    var api = new mw.Api(), out = [];
    function loop(cmcontinue){
      var p = { action:'query', list:'categorymembers', cmtitle:'Kategorie:'+cat,
                cmnamespace:0, cmlimit: Math.min(limit,200), format:'json' };
      if (cmcontinue) p.cmcontinue = cmcontinue;
      return api.get(p).then(function(d){
        var arr = get(d,['query','categorymembers'])||[], i;
        for (i=0;i<arr.length;i++){ out.push(arr[i]); if (out.length>=limit) break; }
        var cont = get(d,['continue','cmcontinue']);
        if (cont && out.length<limit) return loop(cont);
        return out;
      });
    }
    return loop();
  }
  function fetchRatingsForContest(pageIds, contest) {
    var api = new mw.Api(), res = {}, i, chunk=50, chunks=[];
    for (i=0;i<pageIds.length;i+=chunk) chunks.push(pageIds.slice(i,i+chunk));
    function step(idx){
      if (idx>=chunks.length) return Promise.resolve(res);
      var ids = chunks[idx];
      return api.get({
        action:'query', prop:'pagerating', pageids: ids.join('|'),
        prcontest: contest, format:'json'
      }).then(function(d){
        var pages = get(d,['query','pages'])||{};
        for (var pid in pages) if (Object.prototype.hasOwnProperty.call(pages,pid)) {
          var pr = pages[pid].pagerating;
          if (!res[pid]) res[pid] = { avg:null, total:0 };
          if (pr && (!('canSee' in pr) || pr.canSee!==0)) {
            var hist = pr.pageRating || {}, total=0, sum=0, k;
            for (k in hist) if (Object.prototype.hasOwnProperty.call(hist,k)) {
              var s = parseInt(k,10), c = parseInt(hist[k],10);
              if (!isNaN(s)&&!isNaN(c)){ total+=c; sum+=s*c; }
            }
            if (total>0) { res[pid] = { avg: Math.round((sum/total)*10)/10, total: total }; }
          }
        }
        return step(idx+1);
      }, function(){ return step(idx+1); });
    }
    return step(0);
  }
  function computeOverall(entry, contests, weights) {
    var wSum=0, wAvgSum=0, present=0, totalVotes=0, i;
    for (i=0;i<contests.length;i++){
      var c = contests[i], sc = entry.scores[c];
      if (sc && sc.avg!==null) { var w = weights[c]||1; wSum+=w; wAvgSum+=sc.avg*w; present++; }
      if (sc && sc.total) totalVotes += sc.total;
    }
    entry.totalVotes = totalVotes;
    entry.overall = (present>0 && wSum>0) ? Math.round((wAvgSum/wSum)*10)/10 : null;
  }
  function renderTopN(container, rows, N) {
    // nur Seiten mit Stimmen
    rows = rows.filter(function(r){ return (r.overall!==null) && (r.totalVotes>0); });
    rows.sort(function(a,b){
      if (a.overall===null && b.overall!==null) return 1;
      if (a.overall!==null && b.overall===null) return -1;
      if (b.overall!==a.overall) return (b.overall - a.overall);
      if (b.totalVotes!==a.totalVotes) return (b.totalVotes - a.totalVotes);
      return a.title.localeCompare(b.title);
    });
    rows = rows.slice(0, N);
    // bauen
    var frag = document.createDocumentFragment();
    for (var i=0;i<rows.length;i++){
      var r = rows[i];
      var item = document.createElement('div'); item.className='whisky-top5__item';
      var rank = document.createElement('div'); rank.className='whisky-top5__rank'; rank.textContent = (i+1);
      var name = document.createElement('div'); name.className='whisky-top5__name';
      var a = document.createElement('a'); a.href = mw.util.getUrl(r.title); a.textContent = r.title; name.appendChild(a);
      var right = document.createElement('div'); right.style.minWidth='160px';
      var mini = document.createElement('div'); mini.className='whisky-mini';
      var track = document.createElement('div'); track.className='whisky-mini__track';
      var fill = document.createElement('div'); fill.className='whisky-mini__fill';
      fill.style.width = Math.max(0, Math.min(100, (r.overall/10)*100)) + '%';
      var val = document.createElement('span'); val.className='whisky-mini__val';
      val.textContent = (r.overall.toFixed ? r.overall.toFixed(1) : (Math.round(r.overall*10)/10));
      track.appendChild(fill); mini.appendChild(track); mini.appendChild(val);
      var votes = document.createElement('div'); votes.className='whisky-top5__votes';
      votes.textContent = r.totalVotes + ' Stimmen';
      right.appendChild(mini);
      right.appendChild(votes);
      item.appendChild(rank);
      item.appendChild(name);
      item.appendChild(right);
      frag.appendChild(item);
    }
    // ersetzen
    while (container.firstChild) container.removeChild(container.firstChild);
    if (rows.length) {
      container.appendChild(frag);
    } else {
      container.textContent = 'Noch keine Bewertungen vorhanden.';
    }
  }
  function bootTop5(root){
    var nodes = (root||document).querySelectorAll('.whisky-top5');
    if (!nodes.length) return;
    for (var n=0;n<nodes.length;n++){
      (function(container){
        if (container.getAttribute('data-top5-init')==='1') return;
        container.setAttribute('data-top5-init','1');
        var cat  = container.getAttribute('data-category') || 'Whisky';
        var lim  = parseInt(container.getAttribute('data-limit') || '300', 10);
        var cnt  = parseInt(container.getAttribute('data-count') || '5', 10);
        var rawC = container.getAttribute('data-contests') || 'NASE,GESCHMACK,ABGANG,GESAMTEINDRUCK';
        var parts = rawC.split(','), contests=[], seen={}, i;
        for (i=0;i<parts.length;i++){ var c=parts[i].replace(/^\s+|\s+$/g,''); if(c && !seen[c]){ contests.push(c); seen[c]=1; } }
        var weights = parseWeights(container.getAttribute('data-weights')||'', contests);
        container.textContent = 'Lade Topliste …';
        fetchCategoryMembers(cat, lim).then(function(members){
          if (!members || !members.length){ container.textContent='Keine Seiten in Kategorie „'+cat+'“.'; return; }
          var pageIds=[], byId={}, i;
          for (i=0;i<members.length;i++){ pageIds.push(String(members[i].pageid)); byId[String(members[i].pageid)]={ pageid:String(members[i].pageid), title:members[i].title, scores:{} }; }
          // nacheinander je Contest
          function loopContest(idx){
            if (idx>=contests.length) return Promise.resolve();
            var contest = contests[idx];
            return fetchRatingsForContest(pageIds, contest).then(function(map){
              for (var pid in map) if (Object.prototype.hasOwnProperty.call(map,pid)) {
                byId[pid].scores[contest] = map[pid];
              }
              return loopContest(idx+1);
            });
          }
          loopContest(0).then(function(){
            var rows=[], pid;
            for (pid in byId) if (Object.prototype.hasOwnProperty.call(byId,pid)) {
              var e = byId[pid]; computeOverall(e, contests, weights); rows.push(e);
            }
            renderTopN(container, rows, cnt);
          }).catch(function(){ container.textContent='Topliste konnte nicht geladen werden.'; });
        }).catch(function(){ container.textContent='Topliste konnte nicht geladen werden.'; });
      })(nodes[n]);
    }
  }
  if (document.readyState==='loading') {
    document.addEventListener('DOMContentLoaded', function(){ bootTop5(document); });
  } else { bootTop5(document); }
  mw.hook('wikipage.content').add(function($c){ if($c && $c[0]) bootTop5($c[0]); });
});