MediaWiki:Common.js: Difference between revisions
Improve Users by Country counter with better UI and empty state handling |
No edit summary |
||
| Line 835: | Line 835: | ||
// End: Users by Country Counter | // End: Users by Country Counter | ||
// ===================================================== | // ===================================================== | ||
// ===== Article Overview Page - Category/Subcategory/Title/Words/Focus Table ===== | |||
(function() { | |||
if (mw.config.get('wgPageName') !== 'Article_Overview') return; | |||
var apiBase = mw.util.wikiScript('api'); | |||
var allRows = []; | |||
function getCategoryMembers(catName, cmtype, continueParam, accumulated, callback) { | |||
var params = { | |||
action: 'query', list: 'categorymembers', | |||
cmtitle: 'Category:' + catName, | |||
cmlimit: 500, cmtype: cmtype, format: 'json' | |||
}; | |||
if (continueParam) params.cmcontinue = continueParam; | |||
$.getJSON(apiBase, params).done(function(data) { | |||
var members = (data.query && data.query.categorymembers) ? data.query.categorymembers : []; | |||
members.forEach(function(m){ accumulated.push(m); }); | |||
if (data.continue && data.continue.cmcontinue) { | |||
getCategoryMembers(catName, cmtype, data.continue.cmcontinue, accumulated, callback); | |||
} else { | |||
callback(accumulated); | |||
} | |||
}).fail(function(){ callback(accumulated); }); | |||
} | |||
function escHtml(str) { | |||
return String(str).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); | |||
} | |||
function renderTable(rows) { | |||
var tbody = document.getElementById('article-overview-body'); | |||
if (!tbody) return; | |||
if (!rows || rows.length === 0) { | |||
tbody.innerHTML = '<tr><td colspan="5" style="padding:10px;text-align:center;color:#aaa;">No articles found.</td></tr>'; | |||
return; | |||
} | |||
var html = ''; | |||
rows.forEach(function(row, i) { | |||
var bg = i % 2 === 0 ? 'rgba(255,255,255,0.03)' : 'rgba(255,255,255,0.07)'; | |||
html += '<tr style="background:' + bg + ';">'; | |||
html += '<td style="padding:6px 10px;border:1px solid #444;">' + escHtml(row.category) + '</td>'; | |||
html += '<td style="padding:6px 10px;border:1px solid #444;">' + escHtml(row.sub) + '</td>'; | |||
html += '<td style="padding:6px 10px;border:1px solid #444;"><a href="' + mw.util.getUrl(row.title) + '">' + escHtml(row.title) + '</a></td>'; | |||
html += '<td style="padding:6px 10px;border:1px solid #444;text-align:right;">' + escHtml(String(row.words)) + '</td>'; | |||
html += '<td style="padding:6px 10px;border:1px solid #444;">' + escHtml(row.focus) + '</td>'; | |||
html += '</tr>'; | |||
}); | |||
tbody.innerHTML = html; | |||
} | |||
function buildTable() { | |||
var status = document.getElementById('overview-status'); | |||
if (status) status.textContent = 'Fetching categories…'; | |||
$.getJSON(apiBase, { action:'query', list:'allcategories', aclimit:500, format:'json' }) | |||
.done(function(data) { | |||
var topCats = (data.query && data.query.allcategories) ? data.query.allcategories.map(function(c){ return c['*']; }) : []; | |||
var rows = []; | |||
var totalCats = topCats.length; | |||
var processed = 0; | |||
if (totalCats === 0) { | |||
var tbody = document.getElementById('article-overview-body'); | |||
if (tbody) tbody.innerHTML = '<tr><td colspan="5" style="padding:10px;text-align:center;color:#aaa;">No categories found.</td></tr>'; | |||
if (status) status.textContent = ''; | |||
return; | |||
} | |||
function checkDone() { | |||
processed++; | |||
if (status) status.textContent = 'Loading… (' + processed + '/' + totalCats + ' categories processed)'; | |||
if (processed === totalCats) { | |||
rows.sort(function(a,b){ | |||
var ca = a.category.toLowerCase(), cb = b.category.toLowerCase(); | |||
if (ca < cb) return -1; if (ca > cb) return 1; | |||
var sa = a.sub.toLowerCase(), sb = b.sub.toLowerCase(); | |||
if (sa < sb) return -1; if (sa > sb) return 1; | |||
return a.title.localeCompare(b.title); | |||
}); | |||
allRows = rows; | |||
renderTable(rows); | |||
if (status) status.textContent = rows.length + ' article entries loaded.'; | |||
} | |||
} | |||
topCats.forEach(function(catName) { | |||
getCategoryMembers(catName, 'page|subcat', null, [], function(members) { | |||
var pages = members.filter(function(m){ return m.ns === 0; }); | |||
var subcats = members.filter(function(m){ return m.ns === 14; }); | |||
if (pages.length === 0 && subcats.length === 0) { | |||
checkDone(); return; | |||
} | |||
var subTotal = pages.length + subcats.length; | |||
var subProcessed = 0; | |||
function subDone() { | |||
subProcessed++; | |||
if (subProcessed >= subTotal) checkDone(); | |||
} | |||
pages.forEach(function(page) { | |||
rows.push({ category: catName, sub: '—', title: page.title, words: 'n/a', focus: catName }); | |||
subDone(); | |||
}); | |||
subcats.forEach(function(subcat) { | |||
var subName = subcat.title.replace('Category:',''); | |||
getCategoryMembers(subName, 'page', null, [], function(subPages) { | |||
subPages.filter(function(m){ return m.ns === 0; }).forEach(function(page) { | |||
rows.push({ category: catName, sub: subName, title: page.title, words: 'n/a', focus: catName }); | |||
}); | |||
subDone(); | |||
}); | |||
}); | |||
}); | |||
}); | |||
}) | |||
.fail(function() { | |||
var tbody = document.getElementById('article-overview-body'); | |||
if (tbody) tbody.innerHTML = '<tr><td colspan="5" style="padding:10px;text-align:center;color:#f55;">Error loading data. Check API access.</td></tr>'; | |||
}); | |||
} | |||
function downloadCSV() { | |||
if (!allRows || allRows.length === 0) { | |||
alert('No data to download yet. Please wait for the table to finish loading.'); | |||
return; | |||
} | |||
var csv = 'Category,Subcategory,Title,Words,Focus\n'; | |||
allRows.forEach(function(row) { | |||
csv += ['category','sub','title','words','focus'].map(function(k){ | |||
return '"' + String(row[k]).replace(/"/g,'""') + '"'; | |||
}).join(',') + '\n'; | |||
}); | |||
var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); | |||
var url = URL.createObjectURL(blob); | |||
var a = document.createElement('a'); | |||
a.href = url; a.download = 'article-overview.csv'; | |||
document.body.appendChild(a); a.click(); | |||
document.body.removeChild(a); | |||
URL.revokeObjectURL(url); | |||
} | |||
$(document).ready(function() { | |||
var btn = document.getElementById('download-csv-btn'); | |||
if (btn) btn.addEventListener('click', downloadCSV); | |||
buildTable(); | |||
}); | |||
})(); | |||