feat(comment-cards): 제외 단어 필터 추가
입력한 단어가 포함된 댓글을 카드·분석 양쪽에서 제외. 쉼표/공백 다중 지정, 대량 댓글 대비 입력 디바운스(250ms). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
28b072df42
commit
528b48280c
@ -49,6 +49,23 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
// 제외 단어: 쉼표/공백으로 구분. 하나라도 포함된 댓글은 카드·분석 모두에서 제외.
|
||||
function getExcludeTerms() {
|
||||
const raw = ($('ccExclude') && $('ccExclude').value) || '';
|
||||
return raw.split(/[,\s]+/).map(s => s.trim().toLowerCase()).filter(Boolean);
|
||||
}
|
||||
function excludeComments(list, terms) {
|
||||
if (!terms || !terms.length) return list;
|
||||
return list.filter(c => {
|
||||
const t = toPlainText(c.text).toLowerCase();
|
||||
return !terms.some(term => t.includes(term));
|
||||
});
|
||||
}
|
||||
function debounce(fn, ms) {
|
||||
let h = null;
|
||||
return function () { clearTimeout(h); h = setTimeout(fn, ms); };
|
||||
}
|
||||
|
||||
function applyFilterSort(cards) {
|
||||
const sort = $('ccSort').value;
|
||||
const minLikes = parseInt($('ccMinLikes').value, 10) || 0;
|
||||
@ -67,7 +84,8 @@
|
||||
|
||||
window.renderCards = function () {
|
||||
const grid = $('cardGrid');
|
||||
let list = applyFilterSort(window.__all);
|
||||
const base = excludeComments(window.__all, getExcludeTerms());
|
||||
let list = applyFilterSort(base);
|
||||
const total = list.length;
|
||||
const capped = total > DISPLAY_CAP;
|
||||
if (capped) list = list.slice(0, DISPLAY_CAP);
|
||||
@ -226,7 +244,9 @@
|
||||
|
||||
function renderAnalytics(all) {
|
||||
const box = $('ccAnalytics');
|
||||
if (!all || !all.length) { box.style.display = 'none'; box.innerHTML = ''; return; }
|
||||
const exTerms = getExcludeTerms();
|
||||
all = excludeComments(all || [], exTerms);
|
||||
if (!all.length) { box.style.display = 'none'; box.innerHTML = ''; return; }
|
||||
|
||||
const weighted = !!($('ccWeighted') && $('ccWeighted').checked);
|
||||
const tlSort = ($('ccTlSort') && $('ccTlSort').value) || 'count';
|
||||
@ -237,7 +257,8 @@
|
||||
const vid = window.__videoId;
|
||||
|
||||
let html = '<div class="cc-an-head"><b>📊 분석</b> '
|
||||
+ '<span class="cc-an-sub">전체 ' + all.length.toLocaleString() + '개 댓글 기준</span>'
|
||||
+ '<span class="cc-an-sub">' + all.length.toLocaleString() + '개 댓글 기준'
|
||||
+ (exTerms.length ? ' · 제외어 적용' : '') + '</span>'
|
||||
+ '<button type="button" class="cc-iconbtn" id="ccAnToggle">접기</button></div>'
|
||||
+ '<div id="ccAnBody">';
|
||||
|
||||
@ -434,6 +455,11 @@
|
||||
$('ccUrl').addEventListener('keydown', (e) => { if (e.key === 'Enter') fetchComments(); });
|
||||
['ccSearch', 'ccSort', 'ccMinLikes', 'ccRepliesOnly'].forEach(id =>
|
||||
$(id).addEventListener('input', () => window.renderCards()));
|
||||
// 제외 단어는 카드+분석 둘 다 갱신. 대량 댓글 대비 디바운스.
|
||||
$('ccExclude').addEventListener('input', debounce(() => {
|
||||
window.renderCards();
|
||||
renderAnalytics(window.__all);
|
||||
}, 250));
|
||||
$('ccMosaic').addEventListener('click', () => {
|
||||
mosaicOn = !mosaicOn;
|
||||
$('ccMosaic').textContent = mosaicOn ? '모자이크 해제' : '전체 모자이크';
|
||||
|
||||
@ -93,6 +93,7 @@
|
||||
|
||||
<div class="cc-toolbar" id="ccFilters" style="display:none;">
|
||||
<input type="text" id="ccSearch" placeholder="🔍 댓글 내용 검색" style="min-width:180px;" />
|
||||
<input type="text" id="ccExclude" placeholder="🚫 제외 단어 (쉼표로 구분)" style="min-width:180px;" />
|
||||
<select id="ccSort">
|
||||
<option value="likes">좋아요순</option>
|
||||
<option value="replies">답글순</option>
|
||||
@ -116,7 +117,7 @@
|
||||
<th:block layout:fragment="script">
|
||||
<!-- DOM→이미지 캡처 (Task 5에서 사용). blur 필터 지원 위해 modern-screenshot 사용. -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/modern-screenshot@4/dist/index.js"></script>
|
||||
<script th:src="@{/js/comment-cards.js(v=20260708b)}"></script>
|
||||
<script th:src="@{/js/comment-cards.js(v=20260708c)}"></script>
|
||||
</th:block>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user