const API = "/api"; let nbId = null, secId = null, pageId = null; let tool = "pen", paths = [], drawing = false; let canvas, ctx; window.onload = function() { canvas = document.getElementById("drawing-canvas"); ctx = canvas.getContext("2d"); resizeCanvas(); initDrawing(); loadNotebooks(); setInterval(savePage, 30000); }; function showRibbonTab(tab) { document.querySelectorAll(".tab-btn").forEach(b => b.classList.remove("active")); document.querySelectorAll(".ribbon-content").forEach(c => c.classList.remove("active")); document.querySelector('[data-tab="'+tab+'"]').classList.add("active"); document.getElementById(tab+"-tab").classList.add("active"); } function showEditor(type) { document.querySelectorAll(".toggle-btn").forEach(b => b.classList.remove("active")); document.querySelectorAll(".editor-panel").forEach(p => p.classList.remove("active")); document.getElementById("btn-"+type).classList.add("active"); document.getElementById(type+"-editor").classList.add("active"); if(type === "draw") setTimeout(resizeCanvas, 100); } function formatText(cmd, val) { document.execCommand(cmd, false, val); } // Insert Table function insertTable() { let html = ''; for(let i=0; i<3; i++) html += ''; html += '
 

'; document.execCommand("insertHTML", false, html); } // Insert Link function insertLink() { let url = prompt("URL du lien:"); if(url) document.execCommand("insertHTML", false, ''+url+''); } // Handle Image function handleImage(input) { if(input.files[0]) { let reader = new FileReader(); reader.onload = e => document.execCommand("insertHTML", false, ''); reader.readAsDataURL(input.files[0]); } } // Drawing function setDrawTool(t) { tool = t; document.querySelectorAll(".tool-btn").forEach(b => b.classList.remove("active")); document.getElementById("tool-"+t).classList.add("active"); } function initDrawing() { canvas.onpointerdown = e => { e.preventDefault(); drawing = true; startDraw(e); }; canvas.onpointermove = e => { if(drawing) moveDraw(e); }; canvas.onpointerup = () => { drawing = false; savePage(); }; canvas.ontouchstart = e => { e.preventDefault(); drawing = true; startDraw(e.touches[0]); }; canvas.ontouchmove = e => { e.preventDefault(); if(drawing) moveDraw(e.touches[0]); }; canvas.ontouchend = () => { drawing = false; }; canvas.onmousedown = e => { drawing = true; startDraw(e); }; canvas.onmousemove = e => { if(drawing) moveDraw(e); }; canvas.onmouseup = () => { drawing = false; }; } function resizeCanvas() { canvas.width = 2000; canvas.height = 2000; redraw(); } function getPos(e) { let rect = canvas.getBoundingClientRect(); return { x: e.clientX - rect.left, y: e.clientY - rect.top, p: e.pressure || 0.5 }; } function startDraw(e) { let pos = getPos(e); if(tool === "eraser") erase(pos); else { let color = document.getElementById("pen-color").value; let w = parseInt(document.getElementById("pen-width").value); paths.push({ points:[pos], color:tool==="highlighter"?rgba(color,.3):color, width:tool==="highlighter"?w*3:w }); redraw(); } } function moveDraw(e) { let pos = getPos(e); if(tool === "eraser") erase(pos); else if(paths.length) { paths[paths.length-1].points.push(pos); redraw(); } } function erase(pos) { paths = paths.filter(p => !p.points.some(pt => dist(pt,pos)<20)); redraw(); } function dist(a,b) { return Math.sqrt((a.x-b.x)**2+(a.y-b.y)**2); } function rgba(hex,a) { let r=parseInt(hex.slice(1,3),16),g=parseInt(hex.slice(3,5),16),b=parseInt(hex.slice(5,7),16); return `rgba(${r},${g},${b},${a})`; } function redraw() { ctx.clearRect(0,0,canvas.width,canvas.height); paths.forEach(p => { if(p.points.length<2) return; ctx.beginPath(); ctx.lineCap="round"; ctx.strokeStyle=p.color; ctx.lineWidth=p.width; ctx.moveTo(p.points[0].x,p.points[0].y); p.points.forEach(pt => ctx.lineTo(pt.x,pt.y)); ctx.stroke(); }); } function clearDrawing() { if(confirm("Effacer?")){ paths=[]; redraw(); savePage(); }} // Zoom function changeZoom(d) { let z = document.getElementById("zoom-level"); let v = parseInt(z.textContent)+d; z.textContent = Math.max(50,Math.min(200,v))+"%"; } // API async function loadNotebooks() { let res = await fetch(API+"/notebooks"); let list = document.getElementById("notebook-list"); list.innerHTML = ""; (await res.json()).forEach(nb => { let li = document.createElement("li"); li.textContent = nb.name; li.style.borderLeft = "3px solid "+nb.color; li.onclick = () => selectNotebook(nb.id, li); list.appendChild(li); }); } async function selectNotebook(id, el) { nbId = id; document.querySelectorAll("#notebook-list li").forEach(l => l.classList.remove("selected")); el.classList.add("selected"); let res = await fetch(API+"/notebooks/"+id+"/sections"); let list = document.getElementById("section-list"); list.innerHTML = ""; (await res.json()).forEach(s => { let li = document.createElement("li"); li.textContent = s.name; li.onclick = () => selectSection(s.id, li); list.appendChild(li); }); } async function selectSection(id, el) { secId = id; document.querySelectorAll("#section-list li").forEach(l => l.classList.remove("selected")); el.classList.add("selected"); let res = await fetch(API+"/sections/"+id+"/pages"); let list = document.getElementById("page-list"); list.innerHTML = ""; (await res.json()).forEach(p => { let li = document.createElement("li"); li.textContent = p.title; li.onclick = () => loadPage(p.id, li); list.appendChild(li); }); } async function loadPage(id, el) { pageId = id; document.querySelectorAll("#page-list li").forEach(l => l.classList.remove("selected")); el.classList.add("selected"); let p = await fetch(API+"/pages/"+id).then(r=>r.json()); document.getElementById("page-title").value = p.title; document.getElementById("rich-editor").innerHTML = p.content || ""; try { paths = JSON.parse(p.drawing_data||"[]"); } catch(e){ paths=[]; } redraw(); } async function savePage() { if(!pageId) return; await fetch(API+"/pages/"+pageId, { method:"PUT", headers:{"Content-Type":"application/json"}, body:JSON.stringify({ title:document.getElementById("page-title").value, content:document.getElementById("rich-editor").innerHTML, drawing_data:JSON.stringify(paths) }) }); document.getElementById("status-text").textContent = "Sauvegardé"; } async function addNotebook() { let name = prompt("Nom:"); if(name) { await fetch(API+"/notebooks", {method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({name,color:"#7719AA"})}); loadNotebooks(); } } async function addSection() { if(!nbId) return alert("Sélectionnez un notebook"); let name = prompt("Nom:"); if(name) { await fetch(API+"/notebooks/"+nbId+"/sections", {method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({name})}); selectNotebook(nbId, document.querySelector("#notebook-list li.selected")); } } async function addPage() { if(!secId) return alert("Sélectionnez une section"); let title = prompt("Titre:"); if(title) { await fetch(API+"/sections/"+secId+"/pages", {method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({title})}); selectSection(secId, document.querySelector("#section-list li.selected")); } }