diff --git a/frontend/assets/js/app.js b/frontend/assets/js/app.js index 3f7e009..4e40733 100644 --- a/frontend/assets/js/app.js +++ b/frontend/assets/js/app.js @@ -69,14 +69,7 @@ async function performLogin(authToken) { if (data.role === 'admin') document.getElementById('settingsBtn').classList.remove('d-none'); document.getElementById('loginOverlay').style.display = 'none'; window.history.replaceState({}, '', '/'); - // Init canvas if not already - if (!canvas) { - canvas = document.getElementById('networkCanvas'); - ctx = canvas.getContext('2d'); - resizeCanvas(); - } - loadTeams().then(() => loadEvents()); - loadNetworkData(); + initApp(); } else { errEl.textContent = data.error || 'Login failed'; errEl.style.display = 'block'; @@ -111,83 +104,85 @@ document.addEventListener('DOMContentLoaded', () => { if (btn) btn.textContent = 'Authenticating...'; performLogin(authToken); } else { - checkSession().then(() => { - canvas = document.getElementById('networkCanvas'); - ctx = canvas.getContext('2d'); - resizeCanvas(); - - loadTeams().then(() => loadEvents()); - loadNetworkData(); - -document.getElementById('saveEvent').addEventListener('click', saveEvent); - document.getElementById('saveNode').addEventListener('click', saveNode); - document.getElementById('saveLink').addEventListener('click', saveLink); - document.getElementById('saveShape').addEventListener('click', saveShape); - document.getElementById('addUserBtn').addEventListener('click', addUser); - document.getElementById('logoutBtn').addEventListener('click', logout); - document.getElementById('teamFilter').addEventListener('change', renderTimeline); - document.getElementById('searchEvents').addEventListener('input', renderTimeline); - document.getElementById('shapeOpacity').addEventListener('input', (e) => { - document.getElementById('opacityVal').textContent = parseFloat(e.target.value).toFixed(2); - }); - - canvas.addEventListener('mousedown', onMouseDown); - canvas.addEventListener('mousemove', onMouseMove); - canvas.addEventListener('mouseup', onMouseUp); - canvas.addEventListener('dblclick', onDblClick); - canvas.addEventListener('contextmenu', (e) => e.preventDefault()); - window.addEventListener('resize', () => { resizeCanvas(); renderNetwork(); }); - - document.addEventListener('keydown', (e) => { - if ((e.ctrlKey || e.metaKey) && e.key === 'c') { - if (!document.activeElement || document.activeElement.tagName !== 'INPUT') { - if (selectedNodeId) copyNode(selectedNodeId); - else if (selectedShapeId) copyShape(selectedShapeId); - } - return; - } - if ((e.ctrlKey || e.metaKey) && e.key === 'v') { - if (!document.activeElement || document.activeElement.tagName !== 'INPUT') { - if (copyBuffer) pasteItem(); - } - return; - } - if ((e.ctrlKey || e.metaKey) && e.key === 'a') { - if (!document.activeElement || document.activeElement.tagName !== 'INPUT') { - e.preventDefault(); - selectedNodeIds = canvasNodes.map(n => n.id); - selectedNodeId = selectedNodeIds.length > 0 ? selectedNodeIds[0] : null; - selectedShapeId = null; - renderNodeList(); renderShapeList(); renderNetwork(); - } - return; - } - if (e.key === 'Delete') { - if (!document.activeElement || document.activeElement.tagName !== 'INPUT') { - if (selectedNodeIds.length > 0) deleteSelectedNodes(); - else if (selectedShapeId) deleteSelectedShape(selectedShapeId); - } - } - if (e.key === 'Escape') { - selectedNodeId = null; selectedNodeIds = []; - selectedShapeId = null; - renderNetwork(); - renderNodeList(); - renderShapeList(); - } - }); - - document.querySelectorAll('[data-bs-toggle="tab"]').forEach(tab => { - tab.addEventListener('shown.bs.tab', () => { - if (tab.id === 'network-tab') { resizeCanvas(); renderNetwork(); } - }); - }); - - document.documentElement.setAttribute('data-bs-theme', 'dark'); - }).catch(() => {}); + checkSession().then(initApp).catch(() => {}); } }); +function initApp() { + canvas = document.getElementById('networkCanvas'); + ctx = canvas.getContext('2d'); + resizeCanvas(); + + loadTeams().then(() => loadEvents()); + loadNetworkData(); + + document.getElementById('saveEvent').addEventListener('click', saveEvent); + document.getElementById('saveNode').addEventListener('click', saveNode); + document.getElementById('saveLink').addEventListener('click', saveLink); + document.getElementById('saveShape').addEventListener('click', saveShape); + document.getElementById('addUserBtn').addEventListener('click', addUser); + document.getElementById('logoutBtn').addEventListener('click', logout); + document.getElementById('teamFilter').addEventListener('change', renderTimeline); + document.getElementById('searchEvents').addEventListener('input', renderTimeline); + document.getElementById('shapeOpacity').addEventListener('input', (e) => { + document.getElementById('opacityVal').textContent = parseFloat(e.target.value).toFixed(2); + }); + + canvas.addEventListener('mousedown', onMouseDown); + canvas.addEventListener('mousemove', onMouseMove); + canvas.addEventListener('mouseup', onMouseUp); + canvas.addEventListener('dblclick', onDblClick); + canvas.addEventListener('contextmenu', (e) => e.preventDefault()); + window.addEventListener('resize', () => { resizeCanvas(); renderNetwork(); }); + + document.addEventListener('keydown', (e) => { + if ((e.ctrlKey || e.metaKey) && e.key === 'c') { + if (!document.activeElement || document.activeElement.tagName !== 'INPUT') { + if (selectedNodeId) copyNode(selectedNodeId); + else if (selectedShapeId) copyShape(selectedShapeId); + } + return; + } + if ((e.ctrlKey || e.metaKey) && e.key === 'v') { + if (!document.activeElement || document.activeElement.tagName !== 'INPUT') { + if (copyBuffer) pasteItem(); + } + return; + } + if ((e.ctrlKey || e.metaKey) && e.key === 'a') { + if (!document.activeElement || document.activeElement.tagName !== 'INPUT') { + e.preventDefault(); + selectedNodeIds = canvasNodes.map(n => n.id); + selectedNodeId = selectedNodeIds.length > 0 ? selectedNodeIds[0] : null; + selectedShapeId = null; + renderNodeList(); renderShapeList(); renderNetwork(); + } + return; + } + if (e.key === 'Delete') { + if (!document.activeElement || document.activeElement.tagName !== 'INPUT') { + if (selectedNodeIds.length > 0) deleteSelectedNodes(); + else if (selectedShapeId) deleteSelectedShape(selectedShapeId); + } + } + if (e.key === 'Escape') { + selectedNodeId = null; selectedNodeIds = []; + selectedShapeId = null; + renderNetwork(); + renderNodeList(); + renderShapeList(); + } + }); + + document.querySelectorAll('[data-bs-toggle="tab"]').forEach(tab => { + tab.addEventListener('shown.bs.tab', () => { + if (tab.id === 'network-tab') { resizeCanvas(); renderNetwork(); } + }); + }); + + document.documentElement.setAttribute('data-bs-theme', 'dark'); +} + function resizeCanvas() { const wrapper = document.getElementById('networkCanvasWrapper'); canvas.width = wrapper.clientWidth;