MediaWiki:Common.js: Unterschied zwischen den Versionen
Admin (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
Admin (Diskussion | Beiträge) 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]); }); | |||
}); | |||