From 528b48280c60c504a67686d3890b61340e11312d Mon Sep 17 00:00:00 2001 From: "hehihoho3@gmail.com" Date: Wed, 8 Jul 2026 16:07:40 +0900 Subject: [PATCH] =?UTF-8?q?feat(comment-cards):=20=EC=A0=9C=EC=99=B8=20?= =?UTF-8?q?=EB=8B=A8=EC=96=B4=20=ED=95=84=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 입력한 단어가 포함된 댓글을 카드·분석 양쪽에서 제외. 쉼표/공백 다중 지정, 대량 댓글 대비 입력 디바운스(250ms). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/main/resources/static/js/comment-cards.js | 32 +++++++++++++++++-- .../resources/templates/comment-cards.html | 3 +- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/main/resources/static/js/comment-cards.js b/src/main/resources/static/js/comment-cards.js index 37b1dc6..63a72f0 100644 --- a/src/main/resources/static/js/comment-cards.js +++ b/src/main/resources/static/js/comment-cards.js @@ -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 = '
📊 분석 ' - + '전체 ' + all.length.toLocaleString() + '개 댓글 기준' + + '' + all.length.toLocaleString() + '개 댓글 기준' + + (exTerms.length ? ' · 제외어 적용' : '') + '' + '
' + '
'; @@ -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 ? '모자이크 해제' : '전체 모자이크'; diff --git a/src/main/resources/templates/comment-cards.html b/src/main/resources/templates/comment-cards.html index 12d193f..0837085 100644 --- a/src/main/resources/templates/comment-cards.html +++ b/src/main/resources/templates/comment-cards.html @@ -93,6 +93,7 @@