MediaWiki:Common.js: Unterschied zwischen den Versionen

Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
Zeile 608: Zeile 608:




/* --- Whisky Top-5 (multi-root, recursive, robust, self-diagnostics, ES5) -- */
/* --- Whisky Top-5 (multi-root, recursive, robust, namespaces, ES5) ------- */
mw.loader.using(['mediawiki.api']).then(function () {
mw.loader.using(['mediawiki.api']).then(function () {


   /* ========= Utilities ========= */
   /* ========== Utils ========== */
   function get(obj, path) {
   function get(obj, path) {
     var cur = obj, i;
     var cur = obj, i;
Zeile 617: Zeile 617:
     return cur;
     return cur;
   }
   }
   function parseWeights(raw, contests) {
   function parseWeights(raw, contests) {
     var map = {}, parts = (raw || '').split(','), i;
     var map = {}, parts = (raw || '').split(','), i;
Zeile 629: Zeile 628:
   }
   }


   function makeStatus(container){
  /* ========== Statusbox im Widget ========== */
     return function(msg, append){
   function makeStatus(container, keep){
       if (append) {
     var box = container.querySelector('.whisky-top5__status');
        container.innerHTML += '<br>' + mw.html.escape(msg);
    if (!box) {
      } else {
       box = document.createElement('div');
        container.textContent = msg;
      box.className = 'whisky-top5__status';
      }
      container.insertBefore(box, container.firstChild || null);
      // Debug zusätzlich in der Konsole aktivieren:
    }
      // console.log('[Top5]', msg);
    function line(txt){ var row = document.createElement('div'); row.textContent = txt; box.appendChild(row); box.scrollTop = box.scrollHeight; }
     };
    function status(msg, append){ if (!append && !keep) box.innerHTML = ''; line(msg); /* console.log('[Top5]', msg); */ }
     status.done = function(delayMs){ if (keep) return; setTimeout(function(){ if (box && box.parentNode) box.parentNode.removeChild(box); }, typeof delayMs==='number'?delayMs:3000); };
    return status;
   }
   }


   /* ========= Robuste Kategorie-Auflösung ========= */
   /* ========== Robuste Kategorie-Auflösung ========== */
   function categoryCandidates(name){
   function categoryCandidates(name){
     var n = (name || '').replace(/^\s+|\s+$/g,'');
     var n = (name || '').replace(/^\s+|\s+$/g,'');
     var variants = {};
     var v = {}, add=function(s){ if (s && !v[s]) v[s]=1; };
    function add(s){ if (s && !variants[s]) variants[s]=1; }
     add(n);
     add(n);
     add(n.replace(/\u2026/g, '...')); // … -> ...
     add(n.replace(/\u2026/g,'...')); // … -> ...
     add(n.replace(/\.{3}/g, '…'));   // ... -> …
     add(n.replace(/\.{3}/g,'…'));     // ... -> …
     add(n.replace(/\u2013/g, '-'));   // – -> -
     add(n.replace(/\u2013/g,'-'));   // – -> -
     add(n.replace(/-/g, '–'));       // - -> –
     add(n.replace(/-/g,'–'));         // - -> –
     add(n.replace(/\s+/g,' '));      // Mehrfach-Leerzeichen glätten
     add(n.replace(/\s+/g,' '));      // Mehrfach-Spaces
     return Object.keys(variants);
     return Object.keys(v);
   }
   }
  // liefert z. B. "Kategorie:Alle A Dream of …" oder null
   function resolveCategoryTitle(api, rawName){
   function resolveCategoryTitle(api, rawName){
     var cands = categoryCandidates(rawName).map(function(n){ return 'Kategorie:' + n; });
     var cands = categoryCandidates(rawName).map(function(n){ return 'Kategorie:' + n; });
     return api.get({ action:'query', titles: cands.join('|'), format:'json' })
     return api.get({ action:'query', titles: cands.join('|'), format:'json' }).then(function(d){
      .then(function(d){
      var pages = get(d,['query','pages']) || {}, pid, p;
        var pages = (d && d.query && d.query.pages) || {}, pid, p;
      for (pid in pages) if (Object.prototype.hasOwnProperty.call(pages,pid)) { p = pages[pid]; if (p && p.pageid && p.ns === 14) return p.title; }
        for (pid in pages) if (Object.prototype.hasOwnProperty.call(pages,pid)) {
      return null;
          p = pages[pid];
    });
          if (p && p.pageid && p.ns === 14) return p.title;
        }
        return null;
      });
   }
   }


   /* ========= Kategorien rekursiv einsammeln (inkl. Subkats) ========= */
   /* ========== Kategorien rekursiv einsammeln (inkl. Subkats, Namespaces) ========== */
   function fetchCategoryMembersRecursiveSingleResolved(api, catTitle, limit, outSet, pages){
  // NIMMT nsStr (z. B. "*", "0|102|14") – zählt alle Nicht-Kategorie-Seiten
   function fetchCategoryMembersRecursiveSingleResolved(api, catTitle, limit, outSet, pages, nsStr){
     var visited = {}, queue = [catTitle];
     var visited = {}, queue = [catTitle];
    var cmNS = (nsStr && nsStr.trim()) ? nsStr.trim() : '0|14';


     function fetchOne(title, cont){
     function fetchOne(title, cont){
       var params = {
       var params = {
         action:'query', list:'categorymembers', cmtitle:title,
         action:'query', list:'categorymembers', cmtitle:title,
         cmnamespace: (container && container.getAttribute && container.getAttribute('data-namespaces')) || '0|14', cmtype:'page|subcat', cmlimit:Math.min(200, limit),
         cmnamespace: cmNS, cmtype:'page|subcat', cmlimit: Math.min(200, limit),
         format:'json'
         format:'json'
       };
       };
Zeile 685: Zeile 681:
         for (i=0;i<cms.length;i++){
         for (i=0;i<cms.length;i++){
           it = cms[i];
           it = cms[i];
           if (it.ns === 0) {
           if (it.ns !== 14) { // alles außer Kategorien ist eine Seite für uns
             var pid = String(it.pageid);
             var pid = String(it.pageid);
             if (!outSet[pid] && pages.length < limit) { outSet[pid]=1; pages.push({ pageid:pid, title:it.title }); }
             if (!outSet[pid] && pages.length < limit) { outSet[pid]=1; pages.push({ pageid:pid, title:it.title }); }
           } else if (it.ns === 14) {
           } else {
             var sub = it.title;
             var sub = it.title;
             if (!visited[sub]) { visited[sub]=1; queue.push(sub); }
             if (!visited[sub]) { visited[sub]=1; queue.push(sub); }
Zeile 702: Zeile 698:
       var next = queue.shift();
       var next = queue.shift();
       if (visited[next]) return loop();
       if (visited[next]) return loop();
       visited[next]=1;
       visited[next] = 1;
       return fetchOne(next).then(loop);
       return fetchOne(next).then(loop);
     }
     }
Zeile 709: Zeile 705:
   }
   }


   function fetchCategoryMembersRecursiveMulti(rootCats, limit, status){
   function fetchCategoryMembersRecursiveMulti(rootCats, limit, status, nsStr){
     var api = new mw.Api();
     var api = new mw.Api();
     var pages = [], outSet = {};
     var pages = [], outSet = {};
Zeile 716: Zeile 712:
     function next(){
     function next(){
       if (idx >= rootCats.length || pages.length >= limit) return Promise.resolve(pages);
       if (idx >= rootCats.length || pages.length >= limit) return Promise.resolve(pages);
       var raw = rootCats[idx++];
       var raw = rootCats[idx++]; if (!raw) return next();
      if (!raw) return next();


       return resolveCategoryTitle(api, raw).then(function(resolved){
       return resolveCategoryTitle(api, raw).then(function(resolved){
         if (!resolved) {
         if (!resolved) { status('Kategorie nicht gefunden: "' + raw + '"', true); return next(); }
          status('Kategorie nicht gefunden: "' + raw + '" (Schreibweise prüfen)', true);
          return next();
        }
         status('Kategorie erkannt: ' + resolved + ' – sammle …', true);
         status('Kategorie erkannt: ' + resolved + ' – sammle …', true);
         var before = pages.length;
         var before = pages.length;
         return fetchCategoryMembersRecursiveSingleResolved(api, resolved, limit, outSet, pages).then(function(){
         return fetchCategoryMembersRecursiveSingleResolved(api, resolved, limit, outSet, pages, nsStr).then(function(){
           var added = pages.length - before;
           var added = pages.length - before;
           status('→ gefunden in "' + resolved + '": ' + added + ' Seiten (kumuliert: ' + pages.length + ')', true);
           status('→ gefunden in "' + resolved + '": ' + added + ' Seiten (kumuliert: ' + pages.length + ')', true);
Zeile 737: Zeile 729:
   }
   }


   /* ========= Ratings laden / auswerten ========= */
   /* ========== Ratings laden / auswerten ========== */
   function fetchRatingsForContest(pageIds, contest, includeHidden) {
   function fetchRatingsForContest(pageIds, contest, includeHidden) {
     var api = new mw.Api(), res = {}, i, chunk = 50, chunks = [];
     var api = new mw.Api(), res = {}, i, chunk = 50, chunks = [];
Zeile 779: Zeile 771:
   }
   }


   /* ========= Render ========= */
   /* ========== Render ========== */
   function renderTopN(container, rows, N, minVotes) {
   function renderTopN(container, rows, N, minVotes) {
    // Statusbox parken, falls keep aktiv
    var keep = (container.getAttribute && container.getAttribute('data-keep-status') === 'true');
    var statusBox = keep ? container.querySelector('.whisky-top5__status') : null;
     rows = rows.filter(function(r){ return (r.overall !== null) && (r.totalVotes >= minVotes); });
     rows = rows.filter(function(r){ return (r.overall !== null) && (r.totalVotes >= minVotes); });
     rows.sort(function(a,b){
     rows.sort(function(a,b){
Zeile 790: Zeile 786:
     });
     });
     rows = rows.slice(0, N);
     rows = rows.slice(0, N);
    while (container.firstChild) container.removeChild(container.firstChild);
    if (statusBox) container.appendChild(statusBox);
    if (!rows.length) { container.appendChild(document.createTextNode('Noch keine Bewertungen vorhanden.')); return; }


     var frag = document.createDocumentFragment(), i, r, item, rank, name, a, right, mini, track, fill, val, votes;
     var frag = document.createDocumentFragment(), i, r, item, rank, name, a, right, mini, track, fill, val, votes;
Zeile 820: Zeile 821:
       frag.appendChild(item);
       frag.appendChild(item);
     }
     }
 
     container.appendChild(frag);
     while (container.firstChild) container.removeChild(container.firstChild);
    if (rows.length) container.appendChild(frag); else container.textContent = 'Noch keine Bewertungen vorhanden.';
   }
   }


   /* ========= Boot ========= */
   /* ========== Boot ========== */
   function bootTop5(root) {
   function bootTop5(root) {
     var nodes = (root || document).querySelectorAll('.whisky-top5');
     var nodes = (root || document).querySelectorAll('.whisky-top5');
Zeile 834: Zeile 833:
       container.setAttribute('data-top5-init','1');
       container.setAttribute('data-top5-init','1');


       // Kategorien einlesen (Zeilenumbruch ODER Semikolon getrennt)
       // Kategorien (Zeilenumbruch ODER Semikolon getrennt)
       var rawCats = container.getAttribute('data-categories') || container.getAttribute('data-category') || '';
       var rawCats = container.getAttribute('data-categories') || container.getAttribute('data-category') || '';
       var parts = rawCats.split(/\n|;/), rootCats = [], i;
       var parts = rawCats.split(/\n|;/), rootCats = [], i;
       for (i=0;i<parts.length;i++){ var nm = parts[i].replace(/^\s+|\s+$/g,''); if (nm) rootCats.push(nm); }
       for (i=0;i<parts.length;i++){ var nm = parts[i].replace(/^\s+|\s+$/g,''); if (nm) rootCats.push(nm); }
      if (!rootCats.length) { container.textContent = 'Keine Kategorien angegeben.'; return; }


       var lim = parseInt(container.getAttribute('data-limit') || '2000', 10);
       var lim = parseInt(container.getAttribute('data-limit') || '2000', 10);
Zeile 843: Zeile 843:
       var minVotes = parseInt(container.getAttribute('data-min-votes') || '1', 10);
       var minVotes = parseInt(container.getAttribute('data-min-votes') || '1', 10);
       var includeHidden = (container.getAttribute('data-include-hidden') === 'true');
       var includeHidden = (container.getAttribute('data-include-hidden') === 'true');
      var nsStr = container.getAttribute('data-namespaces') || '0|14'; // z. B. "*", "0|102|14"


       var rawC = container.getAttribute('data-contests') || 'NASE,GESCHMACK,ABGANG,GESAMTEINDRUCK';
       var rawC = container.getAttribute('data-contests') || 'NASE,GESCHMACK,ABGANG,GESAMTEINDRUCK';
Zeile 849: Zeile 850:
       var weights = parseWeights(container.getAttribute('data-weights') || '', contests);
       var weights = parseWeights(container.getAttribute('data-weights') || '', contests);


       var status = makeStatus(container);
       var keep = (container.getAttribute('data-keep-status') === 'true');
       if (!rootCats.length) { status('Keine Kategorien angegeben.'); return; }
       var status = makeStatus(container, keep);
 
       status('Sammle Seiten …');
       status('Sammle Seiten …');


       // 1) Seiten aus allen Root-Kategorien (rekursiv) einsammeln
       // 1) Artikel einsammeln
       fetchCategoryMembersRecursiveMulti(rootCats, lim, status).then(function(members){
       fetchCategoryMembersRecursiveMulti(rootCats, lim, status, nsStr).then(function(members){
         status('Gefundene Seiten gesamt: ' + (members ? members.length : 0) + ' – lade Bewertungen …', true);
         status('Gefundene Seiten gesamt: ' + (members ? members.length : 0) + ' – lade Bewertungen …', true);
         if (!members || !members.length) { status('Keine passenden Seiten gefunden.', true); return; }
         if (!members || !members.length) { status('Keine passenden Seiten gefunden.', true); return; }
Zeile 883: Zeile 883:
           }
           }
           renderTopN(container, rows, cnt, minVotes);
           renderTopN(container, rows, cnt, minVotes);
          status.done(keep ? 0 : 3000);
         }
         }


Zeile 897: Zeile 898:


});
});