80 lines
3.7 KiB
JavaScript
80 lines
3.7 KiB
JavaScript
/* ============================================================
|
|
library.js — Papers 탭 (논문 테이블 + 발굴 신규 논문)
|
|
============================================================ */
|
|
(function () {
|
|
'use strict';
|
|
let papers = [], filtered = [], page = 1, sortCol = 'pubYear', sortDir = -1;
|
|
let paperTargets = {};
|
|
const PAGE = 20;
|
|
function el(id) { return document.getElementById(id); }
|
|
|
|
function init() {
|
|
papers = (Store.analysis && Store.analysis.papers) || [];
|
|
// 논문 → 표적 단백질 역색인 (카탈로그 근거 기반)
|
|
Store.catalog.proteins.forEach(p => (p.evidence_paper_ids || []).forEach(id => {
|
|
(paperTargets[id] = paperTargets[id] || []).push(p.gene);
|
|
}));
|
|
|
|
const disSel = el('filter-disease'), ySel = el('filter-year');
|
|
[...new Set(papers.map(p => p.disease).filter(Boolean))].sort().forEach(d => disSel.add(new Option(d, d)));
|
|
[...new Set(papers.map(p => p.pubYear).filter(y => /^\d{4}$/.test(y)))].sort().reverse().forEach(y => ySel.add(new Option(y, y)));
|
|
|
|
el('search-input').addEventListener('input', apply);
|
|
disSel.addEventListener('change', apply);
|
|
ySel.addEventListener('change', apply);
|
|
document.querySelectorAll('#tab-papers .sortable').forEach(th => th.onclick = () => {
|
|
const c = th.dataset.col; if (sortCol === c) sortDir *= -1; else { sortCol = c; sortDir = 1; } apply();
|
|
});
|
|
el('btn-prev').onclick = () => { if (page > 1) { page--; renderTable(); } };
|
|
el('btn-next').onclick = () => { if (page * PAGE < filtered.length) { page++; renderTable(); } };
|
|
renderNewPapers();
|
|
apply();
|
|
}
|
|
|
|
function apply() {
|
|
const q = el('search-input').value.trim().toLowerCase();
|
|
const dis = el('filter-disease').value, yr = el('filter-year').value;
|
|
filtered = papers.filter(p => {
|
|
if (dis && p.disease !== dis) return false;
|
|
if (yr && p.pubYear !== yr) return false;
|
|
if (q && !((p.title || '').toLowerCase().includes(q) || (p.abstract || '').toLowerCase().includes(q))) return false;
|
|
return true;
|
|
});
|
|
filtered.sort((a, b) => {
|
|
const x = (a[sortCol] || ''), y = (b[sortCol] || '');
|
|
return (x < y ? -1 : x > y ? 1 : 0) * sortDir;
|
|
});
|
|
page = 1; renderTable();
|
|
}
|
|
|
|
function renderTable() {
|
|
el('table-count').textContent = filtered.length;
|
|
const start = (page - 1) * PAGE;
|
|
const rows = filtered.slice(start, start + PAGE);
|
|
el('papers-tbody').innerHTML = rows.length ? rows.map(p => {
|
|
const tg = (paperTargets[p.id] || []).slice(0, 6);
|
|
return `<tr>
|
|
<td>${p.pubYear || '—'}</td>
|
|
<td class="title-cell">${p.title || ''}</td>
|
|
<td><span class="badge small">${p.disease || '—'}</span></td>
|
|
<td><div class="targets-cell">${tg.map(g => `<span class="tg" data-gene="${g}">${g}</span>`).join('') || '—'}</div></td>
|
|
</tr>`;
|
|
}).join('') : '<tr><td colspan="4" class="loading-row">결과 없음</td></tr>';
|
|
el('papers-tbody').querySelectorAll('.tg').forEach(t => t.onclick = () => window.openProtein(t.dataset.gene));
|
|
el('page-info').textContent = `${page} / ${Math.max(1, Math.ceil(filtered.length / PAGE))}`;
|
|
el('btn-prev').disabled = page <= 1;
|
|
el('btn-next').disabled = page * PAGE >= filtered.length;
|
|
}
|
|
|
|
function renderNewPapers() {
|
|
const np = (Store.extras && Store.extras.new_papers) || [];
|
|
el('newpapers-list').innerHTML = np.slice(0, 24).map(p => `
|
|
<div class="newpaper-card">
|
|
<div class="np-title">${p.title || ''}</div>
|
|
<div class="np-meta">${p.year || ''} · 표적 <span class="np-target">${p.target || '—'}</span>${p.note ? ' · ' + p.note : ''}</div>
|
|
</div>`).join('') || '<span class="panel-subtitle">발굴된 신규 논문 없음</span>';
|
|
}
|
|
|
|
window.LibraryTab = { init };
|
|
})();
|