${esc(kindLabel)}
${esc(title)}
${lead ? `${esc(lead)}
` : ''}
${insightPanel}
${recallPanel}
${sectionPanel}
${reviewPanel}
${notePanel}
${principlePanel}
${notePanel}
${principlePanel}
${reviewPanel}
`;
}
function bindArticle(container, handlers) {
container.querySelector('#noteBack')?.addEventListener('click', handlers.onBack);
container.querySelector('#noteGraphBtn')?.addEventListener('click', handlers.onGraph);
container.querySelectorAll('.principle-chip[data-note-id], .la-link[data-note-id]').forEach(btn => {
btn.addEventListener('click', () => handlers.openNote(btn.dataset.noteKind, btn.dataset.noteId));
});
container.querySelectorAll('.la-tool-card[data-view]').forEach(btn => {
btn.addEventListener('click', () => handlers.goView(btn.dataset.view));
});
container.querySelectorAll('.learn-tab[data-tab]').forEach(btn => {
btn.addEventListener('click', () => {
const tab = btn.dataset.tab;
container.querySelectorAll('.learn-tab').forEach(x => x.classList.toggle('on', x === btn));
container.querySelectorAll('.learn-tab-panel').forEach(p => { p.hidden = p.dataset.panel !== tab; });
});
});
container.querySelectorAll('.recall-toggle').forEach(btn => {
btn.addEventListener('click', () => {
const ans = btn.parentElement.querySelector('.recall-a');
const open = ans.hidden;
ans.hidden = !open;
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
btn.textContent = open ? '收起答案' : '看參考答案';
});
});
container.querySelectorAll('.review-step').forEach(btn => {
btn.addEventListener('click', () => {
btn.parentElement.querySelectorAll('.review-step').forEach(x => x.classList.toggle('on', x === btn));
});
});
container.querySelectorAll('.save-personal-note').forEach(btn => {
btn.addEventListener('click', () => {
const panel = btn.closest('.personal-note-panel');
const input = panel?.querySelector('.personal-note-input');
const key = input?.dataset.noteKey;
if (!key) return;
const title = container.querySelector('.la-title')?.textContent?.trim() || '';
const parts = key.split(':');
const payload = {
key, title, kind: parts[1] || '', id: parts.slice(2).join(':'),
text: input.value.trim(), updatedAt: new Date().toISOString(),
};
if (payload.text) localStorage.setItem(key, JSON.stringify(payload));
else localStorage.removeItem(key);
const status = panel.querySelector('.personal-note-status');
if (status) status.textContent = payload.text ? '已儲存' : '已清空';
});
});
container.querySelectorAll('.la-toc a').forEach(a => {
a.addEventListener('click', e => {
e.preventDefault();
const el = container.querySelector(a.getAttribute('href'));
el?.scrollIntoView({ behavior: 'smooth', block: 'start' });
});
});
}
function groupPrinciples(principles) {
const groups = PRINCIPLE_GROUPS.map(g => ({ ...g, items: [] }));
const other = { id: 'other', label: '其他', items: [] };
for (const p of principles || []) {
const title = cleanPrincipleTitle(p.title);
const hit = groups.find(g => g.re.test(title));
(hit || other).items.push({ ...p, cleanTitle: title });
}
const out = groups.filter(g => g.items.length);
if (other.items.length) out.push(other);
return out;
}
function renderPrincipleGroups(principles, esc) {
const groups = groupPrinciples(principles);
return groups.map(g => `