document.addEventListener('DOMContentLoaded', () => { const textId = window.location.pathname.split('/').pop(); fetch('/api/texts/' + textId) .then(res => res.json()) .then(text => { const h1 = document.createElement('h1'); h1.textContent = text.name; document.getElementById('text-detail').appendChild(h1); return fetchAndRenderNodes(textId); }); }); function fetchAndRenderNodes(textId) { return fetch('/api/nodes/' + textId) .then(res => res.json()) .then(nodes => { const existing = document.querySelector('#text-detail > ul'); if (existing) existing.remove(); const tree = buildTree(nodes); const ul = renderTree(tree, textId); document.getElementById('text-detail').appendChild(ul); }); } function buildTree(nodes) { const map = {}; nodes.forEach(node => { map[node.id] = { ...node, children: [] }; }); const roots = []; nodes.forEach(node => { if (node.parentNodeId === null) { roots.push(map[node.id]); } else if (map[node.parentNodeId]) { map[node.parentNodeId].children.push(map[node.id]); } }); return roots; } function renderTree(nodes) { const ul = document.createElement('ul'); nodes.forEach(node => { const li = document.createElement('li'); li.textContent = node.title; if (node.children.length > 0) { li.appendChild(renderTree(node.children)); } ul.appendChild(li); }); return ul; }