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, textId) { const ul = document.createElement('ul'); nodes.forEach(node => { const li = document.createElement('li'); const titleSpan = document.createElement('span'); titleSpan.textContent = node.title; li.appendChild(titleSpan); const addBtn = document.createElement('button'); addBtn.textContent = 'Add child'; addBtn.className = 'add-child'; addBtn.addEventListener('click', () => toggleAddForm(li, node.id, textId)); li.appendChild(addBtn); if (node.children.length > 0) { li.appendChild(renderTree(node.children, textId)); } ul.appendChild(li); }); return ul; } function toggleAddForm(li, parentNodeId, textId) { const existing = li.querySelector('input.child-title'); if (existing) { existing.remove(); li.querySelector('button.save-child').remove(); return; } const input = document.createElement('input'); input.type = 'text'; input.className = 'child-title'; input.placeholder = 'Node title'; const saveBtn = document.createElement('button'); saveBtn.textContent = 'Save'; saveBtn.className = 'save-child'; saveBtn.addEventListener('click', () => { const title = input.value.trim(); if (!title) return; fetch('/api/nodes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ textId: parseInt(textId), title, parentNodeId }), }) .then(res => { if (!res.ok) throw new Error('Failed to create node'); return res.json(); }) .then(() => fetchAndRenderNodes(textId)); }); li.appendChild(input); li.appendChild(saveBtn); }