MediaWiki:Common.js: Unterschied zwischen den Versionen
Admin (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
Admin (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
| Zeile 608: | Zeile 608: | ||
/* --- Whisky Top-5 (rekursiv | /* --- Whisky Top-5 (mehrere Root-Kategorien, rekursiv, ES5) ---------------- */ | ||
mw.loader.using(['mediawiki.api']).then(function () { | mw.loader.using(['mediawiki.api']).then(function () { | ||
// | // Utility: sicheres get(obj, ['a','b']) | ||
function get(obj, path) { | function get(obj, path) { | ||
var cur = obj, i; | var cur = obj, i; | ||
| Zeile 638: | Zeile 638: | ||
} | } | ||
// | // Eine Kategorie (inkl. Subkategorien) einsammeln – BFS | ||
function | function fetchCategoryMembersRecursiveSingle(rootCat, limit, outSet, pages) { | ||
var api = new mw.Api(); | var api = new mw.Api(); | ||
var | var visited = {}; | ||
var queue = ['Kategorie:' + rootCat]; | var queue = ['Kategorie:' + rootCat]; | ||
function | function fetchOne(catTitle, cmcontinue) { | ||
var params = { | var params = { | ||
action: 'query', | action: 'query', | ||
list: 'categorymembers', | list: 'categorymembers', | ||
cmtitle: catTitle, | cmtitle: catTitle, | ||
cmnamespace: '0|14', | cmnamespace: '0|14', // Artikel + Kategorien | ||
cmtype: 'page|subcat', | cmtype: 'page|subcat', | ||
cmlimit: Math.min(200, limit), | cmlimit: Math.min(200, limit), | ||
| Zeile 659: | Zeile 658: | ||
return api.get(params).then(function (data) { | return api.get(params).then(function (data) { | ||
var cms = get(data, ['query', 'categorymembers']) || []; | var cms = get(data, ['query', 'categorymembers']) || []; | ||
var i; | var i, it; | ||
for (i = 0; i < cms.length; i++) { | for (i = 0; i < cms.length; i++) { | ||
it = cms[i]; | |||
if ( | if (it.ns === 0) { // Artikel | ||
if (pages.length < limit) pages.push({ pageid: | var pid = String(it.pageid); | ||
} else if ( | if (!outSet[pid] && pages.length < limit) { | ||
var | outSet[pid] = true; | ||
if (! | pages.push({ pageid: pid, title: it.title }); | ||
} | |||
queue.push( | } else if (it.ns === 14) { // Subkat | ||
var sub = it.title; | |||
if (!visited[sub]) { | |||
visited[sub] = true; | |||
queue.push(sub); | |||
} | } | ||
} | } | ||
} | } | ||
var cont = get(data, ['continue', 'cmcontinue']); | var cont = get(data, ['continue', 'cmcontinue']); | ||
if (cont && pages.length < limit) | if (cont && pages.length < limit) return fetchOne(catTitle, cont); | ||
return null; | return null; | ||
}); | }); | ||
| Zeile 682: | Zeile 682: | ||
function loop() { | function loop() { | ||
if (pages.length >= limit || queue.length === 0) { | if (pages.length >= limit || !queue.length) return Promise.resolve(); | ||
var next = queue.shift(); | |||
if (visited[next]) return loop(); | |||
visited[next] = true; | |||
return fetchOne(next).then(loop); | |||
} | |||
return loop(); | |||
} | |||
// Mehrere Root-Kategorien verarbeiten | |||
function fetchCategoryMembersRecursiveMulti(rootCats, limit) { | |||
var pages = []; // {pageid, title} | |||
var outSet = {}; // dedupe per PageID | |||
var i = 0; | |||
function nextCat() { | |||
if (i >= rootCats.length || pages.length >= limit) { | |||
return Promise.resolve(pages); | return Promise.resolve(pages); | ||
} | } | ||
var | var cat = rootCats[i++]; | ||
if ( | if (!cat) return nextCat(); | ||
return fetchCategoryMembersRecursiveSingle(cat, limit, outSet, pages).then(nextCat); | |||
return | |||
} | } | ||
return | return nextCat(); | ||
} | } | ||
// | // RatePage-Daten für einen Contest holen (pageIds batched) | ||
function fetchRatingsForContest(pageIds, contest, includeHidden) { | function fetchRatingsForContest(pageIds, contest, includeHidden) { | ||
var api = new mw.Api(); | var api = new mw.Api(); | ||
var res = {}; // pageId -> { avg, total } | var res = {}; // pageId -> {avg, total} | ||
var i, chunk = 50, chunks = []; | var i, chunk = 50, chunks = []; | ||
for (i = 0; i < pageIds.length; i += chunk) chunks.push(pageIds.slice(i, i + chunk)); | for (i = 0; i < pageIds.length; i += chunk) chunks.push(pageIds.slice(i, i + chunk)); | ||
| Zeile 705: | Zeile 720: | ||
if (idx >= chunks.length) return Promise.resolve(res); | if (idx >= chunks.length) return Promise.resolve(res); | ||
var ids = chunks[idx]; | var ids = chunks[idx]; | ||
return api.get({ | return api.get({ | ||
action: 'query', | action: 'query', | ||
| Zeile 719: | Zeile 733: | ||
if (!res[pid]) res[pid] = { avg: null, total: 0 }; | if (!res[pid]) res[pid] = { avg: null, total: 0 }; | ||
if (pr && (includeHidden || !('canSee' in pr) || pr.canSee !== 0)) { | if (pr && (includeHidden || !('canSee' in pr) || pr.canSee !== 0)) { | ||
hist = pr.pageRating || {}; | hist = pr.pageRating || {}; | ||
total = 0; sum = 0; | total = 0; sum = 0; | ||
for (k in hist) if (Object.prototype.hasOwnProperty.call(hist, k)) { | for (k in hist) if (Object.prototype.hasOwnProperty.call(hist, k)) { | ||
| Zeile 725: | Zeile 739: | ||
if (!isNaN(s) && !isNaN(c)) { total += c; sum += s * c; } | if (!isNaN(s) && !isNaN(c)) { total += c; sum += s * c; } | ||
} | } | ||
if (total > 0) | if (total > 0) res[pid] = { avg: Math.round((sum / total) * 10) / 10, total: total }; | ||
} | } | ||
} | } | ||
return step(idx + 1); | return step(idx + 1); | ||
}, function () { | }, function () { return step(idx + 1); }); | ||
} | } | ||
return step(0); | return step(0); | ||
} | } | ||
// | // Gesamtwertung + Stimmen summieren | ||
function computeOverall(entry, contests, weights) { | function computeOverall(entry, contests, weights) { | ||
var wSum = 0, wAvgSum = 0, present = 0, totalVotes = 0, i; | var wSum = 0, wAvgSum = 0, present = 0, totalVotes = 0, i, sc, w; | ||
for (i = 0; i < contests.length; i++) { | for (i = 0; i < contests.length; i++) { | ||
sc = entry.scores[contests[i]]; | |||
if (sc && sc.avg !== null) { | if (sc && sc.avg !== null) { | ||
w = (typeof weights[contests[i]] === 'number') ? weights[contests[i]] : 1; | |||
wSum += w; | wSum += w; | ||
wAvgSum += sc.avg * w; | wAvgSum += sc.avg * w; | ||
| Zeile 757: | Zeile 766: | ||
} | } | ||
// | // Rendern | ||
function renderTopN(container, rows, N, minVotes) { | function renderTopN(container, rows, N, minVotes) { | ||
rows = rows.filter(function (r) { | rows = rows.filter(function (r) { | ||
return (r.overall !== null) && (r.totalVotes >= minVotes); | return (r.overall !== null) && (r.totalVotes >= minVotes); | ||
}); | }); | ||
rows.sort(function (a, b) { | rows.sort(function (a, b) { | ||
if (a.overall === null && b.overall !== null) return 1; | if (a.overall === null && b.overall !== null) return 1; | ||
if (a.overall !== null && b.overall === null) return -1; | if (a.overall !== null && b.overall === null) return -1; | ||
if (b.overall !== a.overall) return | if (b.overall !== a.overall) return b.overall - a.overall; | ||
if (b.totalVotes !== a.totalVotes) return | if (b.totalVotes !== a.totalVotes) return b.totalVotes - a.totalVotes; | ||
return a.title.localeCompare(b.title); | return a.title.localeCompare(b.title); | ||
}); | }); | ||
| Zeile 833: | Zeile 840: | ||
} | } | ||
// Boot: findet .whisky-top5 | // Boot: findet .whisky-top5 und rendert sie | ||
function bootTop5(root) { | function bootTop5(root) { | ||
var nodes = (root || document).querySelectorAll('.whisky-top5'); | var nodes = (root || document).querySelectorAll('.whisky-top5'); | ||
if (!nodes.length) return; | if (!nodes.length) return; | ||
for (var n = 0; n < nodes.length; n++) (function (container) { | |||
for (n = 0; n < nodes.length; n++) (function (container) { | |||
if (container.getAttribute('data-top5-init') === '1') return; | if (container.getAttribute('data-top5-init') === '1') return; | ||
container.setAttribute('data-top5-init', '1'); | container.setAttribute('data-top5-init', '1'); | ||
var | // Kategorienliste einlesen (Zeilenumbruch oder Semikolon-getrennt) | ||
var lim = parseInt(container.getAttribute('data-limit') || ' | var raw = container.getAttribute('data-categories') || container.getAttribute('data-category') || ''; | ||
var parts = raw.split(/\n|;/); | |||
var rootCats = []; | |||
for (var i = 0; i < parts.length; i++) { | |||
var name = parts[i].replace(/^\s+|\s+$/g, ''); | |||
if (name) rootCats.push(name); | |||
} | |||
if (!rootCats.length) { container.textContent = 'Keine Kategorien angegeben.'; return; } | |||
var lim = parseInt(container.getAttribute('data-limit') || '2000', 10); | |||
var cnt = parseInt(container.getAttribute('data-count') || '5', 10); | var cnt = parseInt(container.getAttribute('data-count') || '5', 10); | ||
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 rawC = container.getAttribute('data-contests') || 'NASE,GESCHMACK,ABGANG,GESAMTEINDRUCK'; | var rawC = container.getAttribute('data-contests') || 'NASE,GESCHMACK,ABGANG,GESAMTEINDRUCK'; | ||
var | var cParts = rawC.split(','), contests = [], seen = {}; | ||
for (i = 0; i < cParts.length; i++) { | |||
for (i = 0; i < | var c = cParts[i].replace(/^\s+|\s+$/g, ''); | ||
var c = | |||
if (c && !seen[c]) { contests.push(c); seen[c] = 1; } | if (c && !seen[c]) { contests.push(c); seen[c] = 1; } | ||
} | } | ||
| Zeile 860: | Zeile 874: | ||
container.textContent = 'Lade Topliste …'; | container.textContent = 'Lade Topliste …'; | ||
// 1) Alle Artikel aus | // 1) Alle Artikel aus allen Root-Kats rekursiv einsammeln | ||
fetchCategoryMembersRecursiveMulti(rootCats, lim).then(function (members) { | |||
if (!members || !members.length) { | if (!members || !members.length) { | ||
container.textContent = 'Keine Seiten | container.textContent = 'Keine passenden Seiten gefunden.'; | ||
return; | return; | ||
} | } | ||
| Zeile 872: | Zeile 886: | ||
} | } | ||
// 2) | // 2) nacheinander je Contest Ratings holen | ||
function loopContest(idx) { | function loopContest(idx) { | ||
if (idx >= contests.length) return Promise.resolve(); | if (idx >= contests.length) return Promise.resolve(); | ||
| Zeile 886: | Zeile 900: | ||
loopContest(0).then(function () { | loopContest(0).then(function () { | ||
// 3) Gesamt berechnen + | // 3) Gesamt berechnen + rendern | ||
var rows = [], pid, e; | var rows = [], pid, e; | ||
for (pid in byId) if (Object.prototype.hasOwnProperty.call(byId, pid)) { | for (pid in byId) if (Object.prototype.hasOwnProperty.call(byId, pid)) { | ||
| Zeile 893: | Zeile 907: | ||
rows.push(e); | rows.push(e); | ||
} | } | ||
renderTopN(container, rows, cnt, minVotes); | renderTopN(container, rows, cnt, minVotes); | ||
}).catch(function () { | }).catch(function () { | ||