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 (multi-root, recursive, robust, | /* --- Whisky Top-5 (multi-root, recursive, robust, namespaces, ES5) ------- */ | ||
mw.loader.using(['mediawiki.api']).then(function () { | mw.loader.using(['mediawiki.api']).then(function () { | ||
/* ========= | /* ========== 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 ========== */ | ||
function makeStatus(container, keep){ | |||
var box = container.querySelector('.whisky-top5__status'); | |||
if (!box) { | |||
box = document.createElement('div'); | |||
box.className = 'whisky-top5__status'; | |||
container.insertBefore(box, container.firstChild || null); | |||
} | |||
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 | var v = {}, add=function(s){ if (s && !v[s]) v[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- | add(n.replace(/\s+/g,' ')); // Mehrfach-Spaces | ||
return Object.keys( | return Object.keys(v); | ||
} | } | ||
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){ | ||
var pages = get(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; } | |||
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: | 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 == | 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 | } 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(); | ||
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 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); | |||
} | } | ||
/* ========= 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 | // 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 | var keep = (container.getAttribute('data-keep-status') === 'true'); | ||
var status = makeStatus(container, keep); | |||
status('Sammle Seiten …'); | status('Sammle Seiten …'); | ||
// 1) | // 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: | ||
}); | }); | ||