Update F95_BRATR_Management_Ratings_Helper.js
Minimize by default, remember it as well
This commit is contained in:
parent
b3fac15c8f
commit
1796314db6
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name F95 BRATR Management Ratings Helper
|
// @name F95 BRATR Management Ratings Helper
|
||||||
// @namespace Ryahn
|
// @namespace Ryahn
|
||||||
// @version 1.4.2
|
// @version 1.5.1
|
||||||
// @description Triage panel for /bratr-ratings/management: highlight low-effort reviews, filter, export CSV.
|
// @description Triage panel for /bratr-ratings/management: highlight low-effort reviews, filter, export CSV.
|
||||||
// @match https://f95zone.to/bratr-ratings/management*
|
// @match https://f95zone.to/bratr-ratings/management*
|
||||||
// @match https://f95zone.to/bratr-ratings/*/management*
|
// @match https://f95zone.to/bratr-ratings/*/management*
|
||||||
@ -23,7 +23,7 @@
|
|||||||
};
|
};
|
||||||
const csvEscape = s => `"${(s||'').replace(/"/g,'""')}"`;
|
const csvEscape = s => `"${(s||'').replace(/"/g,'""')}"`;
|
||||||
const avg = arr => arr.length ? arr.reduce((a,b)=>a+b,0)/arr.length : 0;
|
const avg = arr => arr.length ? arr.reduce((a,b)=>a+b,0)/arr.length : 0;
|
||||||
const truncate = (s, n=80) => (s.length > n ? s.slice(0, n-1) + '…' : s);
|
const truncate = (s, n=80) => (s && s.length > n ? s.slice(0, n-1) + '…' : (s||''));
|
||||||
|
|
||||||
// Scrape reviews on page; stash stable index i for row->DOM mapping
|
// Scrape reviews on page; stash stable index i for row->DOM mapping
|
||||||
const reviews = $$('.message--review').map((msg, i) => {
|
const reviews = $$('.message--review').map((msg, i) => {
|
||||||
@ -66,15 +66,15 @@
|
|||||||
return { i, node: msg, author, rating, thread, threadUrl, timeIso, timeTxt, bodyTxt, rawLen, effLen, deleted, links };
|
return { i, node: msg, author, rating, thread, threadUrl, timeIso, timeTxt, bodyTxt, rawLen, effLen, deleted, links };
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cliché patterns with labels
|
// Cliché patterns (includes fixed 200 detector)
|
||||||
const cliché = [
|
const cliché = [
|
||||||
{ label: 'good game', rx: /\bgood game\b/i },
|
{ key:'good game', label:'“good game”', rx:/\bgood game\b/i },
|
||||||
{ label: 'very good', rx: /\bit was very good\b/i },
|
{ key:'very good', label:'“it was very good”', rx:/\bit was very good\b/i },
|
||||||
{ label: 'amazing', rx: /\bamazing!?(\b|$)/i },
|
{ key:'amazing', label:'“amazing”', rx:/\bamazing!?(\b|$)/i },
|
||||||
{ label: 'top N', rx: /\btop\s+\d+\b/i },
|
{ key:'top N', label:'“top <number>”', rx:/\btop\s+\d+\b/i },
|
||||||
{ label: 'pretty sex scenes', rx: /\bpretty sex scenes\b/i },
|
{ key:'pretty sex scenes', label:'“pretty sex scenes”', rx:/\bpretty sex scenes\b/i },
|
||||||
{ label: 'downloads flex', rx: /\bdownload(ed)? hundreds of games\b/i },
|
{ key:'downloads flex', label:'“downloaded hundreds of games”', rx:/\bdownload(ed)? hundreds of games\b/i },
|
||||||
{ label: 'mentions 200 (char rule)', rx: /\b200(?:\s*[- ]?(?:char(?:s|acters?)?|word(?:s)?|limit|minimum|min))?\b/i }
|
{ key:'mentions 200', label:'mentions “200” (char/limit/min)', rx:/\b200(?:\s*[- ]?(?:char(?:s|acters?)?|word(?:s)?|limit|minimum|min))?\b/i }
|
||||||
];
|
];
|
||||||
|
|
||||||
// Spam/bypass heuristics
|
// Spam/bypass heuristics
|
||||||
@ -157,28 +157,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Diagnose low-effort
|
// Diagnose low-effort
|
||||||
function diagnoseLowEffort(r, cutoff=200) {
|
function diagnoseLowEffort(r, cutoff=220) {
|
||||||
const reasons = [];
|
const reasons = [];
|
||||||
const body = r.bodyTxt || '';
|
const body = r.bodyTxt || '';
|
||||||
|
|
||||||
if (!r.deleted && (r.effLen || 0) < cutoff) {
|
if (!r.deleted && (r.effLen || 0) < cutoff) {
|
||||||
reasons.push({
|
reasons.push({ code:'LEN', text:`LEN ${r.effLen}<${cutoff}`, tip:`Effective length ${r.effLen} is below cutoff ${cutoff}` });
|
||||||
code: 'LEN',
|
|
||||||
text: `LEN ${r.effLen}<${cutoff}`,
|
|
||||||
tip: `Effective length ${r.effLen} is below cutoff ${cutoff}`
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!r.deleted) {
|
if (!r.deleted) {
|
||||||
cliché.forEach(c => {
|
cliché.forEach(c => {
|
||||||
const m = body.match(c.rx);
|
const m = body.match(c.rx);
|
||||||
if (m) reasons.push({ code: 'CLICHÉ', text: `CLICHÉ: "${truncate(m[0], 28)}"`, tip: `Matched phrase: ${m[0]}` });
|
if (m) reasons.push({ code:'CLICHÉ', text:`CLICHÉ: "${truncate(m[0], 28)}"`, tip:`Matched: ${m[0]}`, key:c.key });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
analyzeSpam(body).forEach(sr => reasons.push(sr));
|
analyzeSpam(body).forEach(sr => reasons.push(sr));
|
||||||
|
|
||||||
if (r.deleted) reasons.push({ code: 'DELETED', text: 'DELETED', tip: 'Author deleted review' });
|
if (r.deleted) reasons.push({ code:'DELETED', text:'DELETED', tip:'Author deleted review' });
|
||||||
|
|
||||||
const low = reasons.some(x => x.code === 'LEN' || x.code === 'CLICHÉ' || x.code === 'SPAM');
|
const low = reasons.some(x => x.code === 'LEN' || x.code === 'CLICHÉ' || x.code === 'SPAM');
|
||||||
return { low, reasons };
|
return { low, reasons };
|
||||||
@ -196,11 +192,13 @@
|
|||||||
<div class="bh-body">
|
<div class="bh-body">
|
||||||
<div class="bh-controls">
|
<div class="bh-controls">
|
||||||
<label>Min ★ <input type="number" step="0.5" min="0" max="5" class="bh-minrating" value="0"></label>
|
<label>Min ★ <input type="number" step="0.5" min="0" max="5" class="bh-minrating" value="0"></label>
|
||||||
<label>Low-effort length cutoff <input type="number" min="0" class="bh-maxlen" value="200"></label>
|
<label>Low-effort length cutoff <input type="number" min="0" class="bh-maxlen" value="220"></label>
|
||||||
<label>User <input type="text" class="bh-user" placeholder="author contains"></label>
|
<label>User <input type="text" class="bh-user" placeholder="author contains"></label>
|
||||||
<label>Date from <input type="datetime-local" class="bh-from"></label>
|
<label>Date from <input type="datetime-local" class="bh-from"></label>
|
||||||
<label>Date to <input type="datetime-local" class="bh-to"></label>
|
<label>Date to <input type="datetime-local" class="bh-to"></label>
|
||||||
<label><input type="checkbox" class="bh-lowonly" checked> Low-effort only</label>
|
<label><input type="checkbox" class="bh-lowonly" checked> Low-effort only</label>
|
||||||
|
<label>Cliché <select class="bh-cliche"><option value="__ALL__">All clichés</option></select></label>
|
||||||
|
<label><input type="checkbox" class="bh-cliche-only"> Only reviews matching selected cliché</label>
|
||||||
<button class="bh-copy">Copy CSV</button>
|
<button class="bh-copy">Copy CSV</button>
|
||||||
<button class="bh-reset">Reset</button>
|
<button class="bh-reset">Reset</button>
|
||||||
</div>
|
</div>
|
||||||
@ -209,10 +207,10 @@
|
|||||||
`;
|
`;
|
||||||
document.body.appendChild(panel);
|
document.body.appendChild(panel);
|
||||||
|
|
||||||
// Styles (+ clickable rows + pulse highlight)
|
// Styles
|
||||||
const css = document.createElement('style');
|
const css = document.createElement('style');
|
||||||
css.textContent = `
|
css.textContent = `
|
||||||
#bratr-helper{position:fixed;right:12px;bottom:12px;width:780px;max-height:70vh;z-index:99999;
|
#bratr-helper{position:fixed;right:12px;bottom:12px;width:820px;max-height:70vh;z-index:99999;
|
||||||
background:#111;border:1px solid #333;border-radius:12px;color:#ddd;font:12px/1.4 system-ui;box-shadow:0 8px 24px rgba(0,0,0,.4)}
|
background:#111;border:1px solid #333;border-radius:12px;color:#ddd;font:12px/1.4 system-ui;box-shadow:0 8px 24px rgba(0,0,0,.4)}
|
||||||
#bratr-helper .bh-head{display:flex;align-items:center;justify-content:space-between;padding:8px 10px;border-bottom:1px solid #2a2a2a}
|
#bratr-helper .bh-head{display:flex;align-items:center;justify-content:space-between;padding:8px 10px;border-bottom:1px solid #2a2a2a}
|
||||||
#bratr-helper .bh-head strong{font-size:13px}
|
#bratr-helper .bh-head strong{font-size:13px}
|
||||||
@ -221,7 +219,7 @@
|
|||||||
#bratr-helper .bh-body{padding:8px}
|
#bratr-helper .bh-body{padding:8px}
|
||||||
#bratr-helper .bh-controls{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}
|
#bratr-helper .bh-controls{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}
|
||||||
#bratr-helper .bh-controls label{display:flex;gap:6px;align-items:center;background:#161616;border:1px solid #2a2a2a;border-radius:8px;padding:4px 8px}
|
#bratr-helper .bh-controls label{display:flex;gap:6px;align-items:center;background:#161616;border:1px solid #2a2a2a;border-radius:8px;padding:4px 8px}
|
||||||
#bratr-helper input{background:#0f0f0f;border:1px solid #333;color:#ddd;border-radius:6px;padding:3px 6px}
|
#bratr-helper input, #bratr-helper select{background:#0f0f0f;border:1px solid #333;color:#ddd;border-radius:6px;padding:3px 6px}
|
||||||
#bratr-helper button.bh-copy,#bratr-helper button.bh-reset{background:#1e1e1e;border:1px solid #444;color:#ddd;border-radius:8px;padding:4px 10px;cursor:pointer}
|
#bratr-helper button.bh-copy,#bratr-helper button.bh-reset{background:#1e1e1e;border:1px solid #444;color:#ddd;border-radius:8px;padding:4px 10px;cursor:pointer}
|
||||||
#bratr-helper .bh-table{overflow:auto;max-height:48vh;border:1px solid #2a2a2a;border-radius:8px}
|
#bratr-helper .bh-table{overflow:auto;max-height:48vh;border:1px solid #2a2a2a;border-radius:8px}
|
||||||
#bratr-helper table{width:100%;border-collapse:collapse}
|
#bratr-helper table{width:100%;border-collapse:collapse}
|
||||||
@ -236,10 +234,7 @@
|
|||||||
#bratr-helper .pill.delet{border-color:#8aa;color:#8aa}
|
#bratr-helper .pill.delet{border-color:#8aa;color:#8aa}
|
||||||
#bratr-helper .pill.spam{border-color:#ff9d00;color:#ff9d00}
|
#bratr-helper .pill.spam{border-color:#ff9d00;color:#ff9d00}
|
||||||
#bratr-helper .links a{margin-right:8px}
|
#bratr-helper .links a{margin-right:8px}
|
||||||
@keyframes bh-pulse {
|
@keyframes bh-pulse {0%{box-shadow:0 0 0 0 rgba(245,180,0,.6);}100%{box-shadow:0 0 0 12px rgba(245,180,0,0);}}
|
||||||
0% { box-shadow: 0 0 0 0 rgba(245,180,0,.6); }
|
|
||||||
100% { box-shadow: 0 0 0 12px rgba(245,180,0,0); }
|
|
||||||
}
|
|
||||||
.bh-target-pulse { animation: bh-pulse 1s ease-out 0s 2; outline: 2px solid #f5b400 !important; }
|
.bh-target-pulse { animation: bh-pulse 1s ease-out 0s 2; outline: 2px solid #f5b400 !important; }
|
||||||
@media (max-width: 880px){#bratr-helper{left:8px;right:8px;width:auto}}
|
@media (max-width: 880px){#bratr-helper{left:8px;right:8px;width:auto}}
|
||||||
`;
|
`;
|
||||||
@ -252,21 +247,54 @@
|
|||||||
lowonly: panel.querySelector('.bh-lowonly'),
|
lowonly: panel.querySelector('.bh-lowonly'),
|
||||||
from: panel.querySelector('.bh-from'),
|
from: panel.querySelector('.bh-from'),
|
||||||
to: panel.querySelector('.bh-to'),
|
to: panel.querySelector('.bh-to'),
|
||||||
|
clicheSel: panel.querySelector('.bh-cliche'),
|
||||||
|
clicheOnly: panel.querySelector('.bh-cliche-only'),
|
||||||
table: panel.querySelector('.bh-table'),
|
table: panel.querySelector('.bh-table'),
|
||||||
metrics: panel.querySelector('.bh-metrics')
|
metrics: panel.querySelector('.bh-metrics')
|
||||||
};
|
};
|
||||||
|
|
||||||
panel.querySelector('.bh-collapse').addEventListener('click', () => {
|
// Populate cliché dropdown
|
||||||
const body = panel.querySelector('.bh-body');
|
const frag = document.createDocumentFragment();
|
||||||
if (body.style.display === 'none') { body.style.display = ''; panel.querySelector('.bh-collapse').textContent = '–'; }
|
cliché.forEach(c => {
|
||||||
else { body.style.display = 'none'; panel.querySelector('.bh-collapse').textContent = '+'; }
|
const opt = document.createElement('option');
|
||||||
|
opt.value = c.key;
|
||||||
|
opt.textContent = c.label;
|
||||||
|
frag.appendChild(opt);
|
||||||
});
|
});
|
||||||
|
ui.clicheSel.appendChild(frag);
|
||||||
|
|
||||||
|
const COLLAPSE_KEY = 'bh-collapsed';
|
||||||
|
const bodyEl = panel.querySelector('.bh-body');
|
||||||
|
const collapseBtn = panel.querySelector('.bh-collapse');
|
||||||
|
|
||||||
|
function setCollapsed(collapsed) {
|
||||||
|
bodyEl.style.display = collapsed ? 'none' : '';
|
||||||
|
collapseBtn.textContent = collapsed ? '+' : '–';
|
||||||
|
try { localStorage.setItem(COLLAPSE_KEY, collapsed ? '1' : '0'); } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
collapseBtn.addEventListener('click', () => {
|
||||||
|
setCollapsed(bodyEl.style.display !== 'none');
|
||||||
|
});
|
||||||
|
|
||||||
|
// initialize from storage; default to collapsed if unset
|
||||||
|
const stored = (typeof localStorage !== 'undefined') ? localStorage.getItem(COLLAPSE_KEY) : null;
|
||||||
|
setCollapsed(stored === null ? true : stored === '1');
|
||||||
panel.querySelector('.bh-reset').addEventListener('click', () => {
|
panel.querySelector('.bh-reset').addEventListener('click', () => {
|
||||||
ui.min.value = 0; ui.maxlen.value = 200; ui.user.value = ''; ui.lowonly.checked = true; ui.from.value = ''; ui.to.value = '';
|
ui.min.value = 0;
|
||||||
|
ui.maxlen.value = 220;
|
||||||
|
ui.user.value = '';
|
||||||
|
ui.lowonly.checked = true;
|
||||||
|
ui.from.value = '';
|
||||||
|
ui.to.value = '';
|
||||||
|
ui.clicheSel.value = '__ALL__';
|
||||||
|
ui.clicheOnly.checked = false;
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
|
|
||||||
['input','change'].forEach(ev => {
|
['input','change'].forEach(ev => {
|
||||||
[ui.min, ui.maxlen, ui.user, ui.lowonly, ui.from, ui.to].forEach(el => el.addEventListener(ev, render));
|
[ui.min, ui.maxlen, ui.user, ui.lowonly, ui.from, ui.to, ui.clicheSel, ui.clicheOnly]
|
||||||
|
.forEach(el => el.addEventListener(ev, render));
|
||||||
});
|
});
|
||||||
|
|
||||||
function withinDates(iso, from, to) {
|
function withinDates(iso, from, to) {
|
||||||
@ -277,6 +305,15 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reviewMatchesSelectedCliche(r) {
|
||||||
|
if (!ui.clicheOnly.checked) return true;
|
||||||
|
const selected = ui.clicheSel.value;
|
||||||
|
if (!selected || selected === '__ALL__') return true;
|
||||||
|
const def = cliché.find(c => c.key === selected);
|
||||||
|
if (!def) return true;
|
||||||
|
return def.rx.test(r.bodyTxt || '');
|
||||||
|
}
|
||||||
|
|
||||||
function currentRows() {
|
function currentRows() {
|
||||||
const min = parseFloat(ui.min.value || '0');
|
const min = parseFloat(ui.min.value || '0');
|
||||||
const maxlen = parseInt(ui.maxlen.value || '0', 10);
|
const maxlen = parseInt(ui.maxlen.value || '0', 10);
|
||||||
@ -289,6 +326,8 @@
|
|||||||
if (Number.isFinite(min) && r.rating != null && r.rating < min) return false;
|
if (Number.isFinite(min) && r.rating != null && r.rating < min) return false;
|
||||||
if (user && !r.author.toLowerCase().includes(user)) return false;
|
if (user && !r.author.toLowerCase().includes(user)) return false;
|
||||||
if (from || to) { if (!withinDates(r.timeIso, from, to)) return false; }
|
if (from || to) { if (!withinDates(r.timeIso, from, to)) return false; }
|
||||||
|
if (!reviewMatchesSelectedCliche(r)) return false;
|
||||||
|
|
||||||
const diag = diagnoseLowEffort(r, maxlen);
|
const diag = diagnoseLowEffort(r, maxlen);
|
||||||
if (lowOnly && !diag.low) return false;
|
if (lowOnly && !diag.low) return false;
|
||||||
return true;
|
return true;
|
||||||
@ -296,11 +335,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
const maxlen = parseInt(ui.maxlen.value || '200', 10);
|
const maxlen = parseInt(ui.maxlen.value || '220', 10);
|
||||||
const live = reviews.filter(r => !r.deleted);
|
const live = reviews.filter(r => !r.deleted);
|
||||||
const lowCount = live.filter(r => diagnoseLowEffort(r, maxlen).low).length;
|
const lowCount = live.filter(r => diagnoseLowEffort(r, maxlen).low).length;
|
||||||
const avgRating = avg(live.map(r => r.rating || 0)).toFixed(2);
|
const avgRating = avg(live.map(r => r.rating || 0)).toFixed(2);
|
||||||
ui.metrics.textContent = `on page: ${reviews.length} • avg ★ ${avgRating} • low-effort flagged: ${lowCount}`;
|
const clicheInfo = ui.clicheOnly.checked
|
||||||
|
? ` • cliché: ${ui.clicheSel.options[ui.clicheSel.selectedIndex]?.text || 'All'}`
|
||||||
|
: '';
|
||||||
|
ui.metrics.textContent = `on page: ${reviews.length} • avg ★ ${avgRating} • low-effort flagged: ${lowCount}${clicheInfo}`;
|
||||||
|
|
||||||
const rows = currentRows();
|
const rows = currentRows();
|
||||||
const html = [`<table><thead><tr>
|
const html = [`<table><thead><tr>
|
||||||
@ -311,6 +353,7 @@
|
|||||||
const low = diag.low;
|
const low = diag.low;
|
||||||
const one = Math.round(r.rating||0) === 1;
|
const one = Math.round(r.rating||0) === 1;
|
||||||
const cls = `${low ? 'low' : ''} ${r.deleted ? 'deleted': ''}`.trim();
|
const cls = `${low ? 'low' : ''} ${r.deleted ? 'deleted': ''}`.trim();
|
||||||
|
|
||||||
const flagHtml = diag.reasons.map(reason => {
|
const flagHtml = diag.reasons.map(reason => {
|
||||||
let pill = 'pill';
|
let pill = 'pill';
|
||||||
if (reason.code === 'LEN' || reason.code === 'CLICHÉ') pill += ' low';
|
if (reason.code === 'LEN' || reason.code === 'CLICHÉ') pill += ' low';
|
||||||
@ -319,6 +362,7 @@
|
|||||||
const tip = reason.tip ? ` title="${reason.tip.replace(/"/g, '"')}"` : '';
|
const tip = reason.tip ? ` title="${reason.tip.replace(/"/g, '"')}"` : '';
|
||||||
return `<span class="${pill}"${tip}>${reason.text}</span>`;
|
return `<span class="${pill}"${tip}>${reason.text}</span>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
html.push(`<tr class="${cls}" data-i="${r.i}">
|
html.push(`<tr class="${cls}" data-i="${r.i}">
|
||||||
<td>${r.author || ''}</td>
|
<td>${r.author || ''}</td>
|
||||||
<td>${r.rating != null ? r.rating.toFixed(2) : ''}</td>
|
<td>${r.rating != null ? r.rating.toFixed(2) : ''}</td>
|
||||||
@ -338,11 +382,12 @@
|
|||||||
html.push(`</tbody></table>`);
|
html.push(`</tbody></table>`);
|
||||||
ui.table.innerHTML = html.join('');
|
ui.table.innerHTML = html.join('');
|
||||||
|
|
||||||
// Bind row click delegation exactly once and keep it
|
// Keep single delegated click handler alive
|
||||||
if (!ui.table._bhBound) {
|
if (!ui.table._bhBound) {
|
||||||
ui.table.addEventListener('click', onRowClick);
|
ui.table.addEventListener('click', onRowClick);
|
||||||
ui.table._bhBound = true;
|
ui.table._bhBound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
retint();
|
retint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,17 +399,16 @@
|
|||||||
const r = reviews[idx];
|
const r = reviews[idx];
|
||||||
if (!r || !r.node) return;
|
if (!r || !r.node) return;
|
||||||
|
|
||||||
// Smooth scroll and pulse
|
|
||||||
r.node.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
r.node.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
r.node.classList.remove('bh-target-pulse');
|
r.node.classList.remove('bh-target-pulse');
|
||||||
void r.node.offsetWidth; // reflow to restart animation
|
void r.node.offsetWidth;
|
||||||
r.node.classList.add('bh-target-pulse');
|
r.node.classList.add('bh-target-pulse');
|
||||||
setTimeout(() => r.node.classList.remove('bh-target-pulse'), 1800);
|
setTimeout(() => r.node.classList.remove('bh-target-pulse'), 1800);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tint live page with reasons as tooltip
|
// Tint live page with reasons as tooltip
|
||||||
function retint() {
|
function retint() {
|
||||||
const maxlen = parseInt(ui.maxlen?.value || '200', 10);
|
const maxlen = parseInt(ui.maxlen?.value || '220', 10);
|
||||||
reviews.forEach(r => {
|
reviews.forEach(r => {
|
||||||
if (r.deleted) {
|
if (r.deleted) {
|
||||||
r.node.style.outline = '';
|
r.node.style.outline = '';
|
||||||
@ -389,7 +433,7 @@
|
|||||||
// Copy CSV of current view, with reasons column
|
// Copy CSV of current view, with reasons column
|
||||||
panel.querySelector('.bh-copy').addEventListener('click', () => {
|
panel.querySelector('.bh-copy').addEventListener('click', () => {
|
||||||
const rows = currentRows();
|
const rows = currentRows();
|
||||||
const maxlen = parseInt(ui.maxlen?.value || '200', 10);
|
const maxlen = parseInt(ui.maxlen?.value || '220', 10);
|
||||||
const header = ['author','rating','thread','threadUrl','timeIso','effLen','rawLen','deleted','low','reasons','body'];
|
const header = ['author','rating','thread','threadUrl','timeIso','effLen','rawLen','deleted','low','reasons','body'];
|
||||||
const lines = [header.join(',')];
|
const lines = [header.join(',')];
|
||||||
rows.forEach(r => {
|
rows.forEach(r => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user