release
This commit is contained in:
72
static/js/stats.js
Normal file
72
static/js/stats.js
Normal file
@@ -0,0 +1,72 @@
|
||||
(function () {
|
||||
const $ = (s, r = document) => r.querySelector(s);
|
||||
const $$ = (s, r = document) => Array.from(r.querySelectorAll(s));
|
||||
|
||||
// Kopiuj: cały widok
|
||||
$('#btn-copy-overview')?.addEventListener('click', async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(document.body.innerText);
|
||||
window.showToast?.({ text: 'Skopiowano podsumowanie.', variant: 'success' });
|
||||
} catch {
|
||||
window.showToast?.({ text: 'Nie udało się skopiować.', variant: 'danger' });
|
||||
}
|
||||
});
|
||||
|
||||
// Eksport CSV z DOM (GEO + REASONS)
|
||||
$('#btn-export-overview')?.addEventListener('click', () => {
|
||||
const lines = [];
|
||||
lines.push('section,key,count,percent');
|
||||
|
||||
// GEO: z tabeli
|
||||
$$('#geo-table tbody tr').forEach(tr => {
|
||||
const tds = tr.querySelectorAll('td');
|
||||
if (tds.length !== 3) return;
|
||||
const country = tds[0]?.innerText.trim();
|
||||
const percent = (tds[1]?.querySelector('.text-secondary')?.innerText.trim() || '').replace('%', '');
|
||||
const count = tds[2]?.innerText.trim();
|
||||
if (country) lines.push(`geo,"${country.replace(/"/g, '""')}",${count},${percent}`);
|
||||
});
|
||||
|
||||
// REASONS: z listy
|
||||
$$('.card:has(.card-header:contains("Przyczyny banów")) .list-group-item').forEach(li => {
|
||||
const label = li.querySelector('.text-truncate')?.getAttribute('title') || li.querySelector('.text-truncate')?.innerText || '';
|
||||
const meta = li.querySelector('.small.text-secondary')?.innerText || ''; // "123 (45.6%)"
|
||||
const m = meta.match(/(\d+)\s*\(([\d.,]+)%\)/);
|
||||
const count = m ? m[1] : '';
|
||||
const percent = m ? m[2].replace(',', '.') : '';
|
||||
if (label) lines.push(`reason,"${label.replace(/"/g, '""')}",${count},${percent}`);
|
||||
});
|
||||
|
||||
const csv = lines.join('\n');
|
||||
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url; a.download = 'stats_overview.csv'; a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
|
||||
// Polyfill :contains dla selektora użytego wyżej (prosty, lokalny)
|
||||
(function addContainsPseudo() {
|
||||
const _matches = Element.prototype.matches;
|
||||
if (!document.querySelector(':contains(dummy)')) {
|
||||
const oldQuerySelectorAll = Document.prototype.querySelectorAll;
|
||||
Document.prototype.querySelectorAll = function (sel) {
|
||||
if (!sel.includes(':contains(')) return oldQuerySelectorAll.call(this, sel);
|
||||
const m = sel.match(/^(.*):has\(\.card-header:contains\("([^"]+)"\)\)\s*(.*)$/);
|
||||
if (m) {
|
||||
const [, pre, text, post] = m;
|
||||
return $$(pre + ' .card').filter(card => {
|
||||
return card.querySelector('.card-header')?.textContent.includes(text);
|
||||
}).flatMap(card => card.querySelectorAll(post || ''));
|
||||
}
|
||||
return oldQuerySelectorAll.call(this, sel);
|
||||
};
|
||||
Element.prototype.matches = function (sel) {
|
||||
if (!sel.includes(':contains(')) return _matches.call(this, sel);
|
||||
const m = sel.match(/^:contains\("([^"]+)"\)$/);
|
||||
if (m) return this.textContent.includes(m[1]);
|
||||
return _matches.call(this, sel);
|
||||
};
|
||||
}
|
||||
})();
|
||||
})();
|
||||
Reference in New Issue
Block a user