window.API = { async get(url) { const r = await fetch(url,{credentials:'same-origin'}); if(!r.ok)throw new Error(await r.text()); return r.json(); }, async post(url,data) { const r = await fetch(url,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data),credentials:'same-origin'}); if(!r.ok)throw new Error(await r.text()); return r.json(); }, async put(url,data) { const r = await fetch(url,{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(data),credentials:'same-origin'}); if(!r.ok)throw new Error(await r.text()); return r.json(); }, async del(url) { const r = await fetch(url,{method:'DELETE',credentials:'same-origin'}); if(!r.ok)throw new Error(await r.text()); return r.json(); } }; window.$ = (sel) => document.querySelector(sel); window.$$ = (sel) => document.querySelectorAll(sel); window.notify = function(msg, type) { var el = document.createElement('div'); el.className = 'notification ' + (type || ''); el.textContent = msg; document.body.appendChild(el); setTimeout(function() { el.remove(); }, 3000); }; window.undoState = null; window.updateUndoBar = function() { API.get('/api/undo/state').then(function(s) { undoState = s; var uBtn = $('.undo-btn'); var rBtn = $('.redo-btn'); var uLabel = $('.undo-label'); if (uBtn) { uBtn.disabled = !s.can_undo; uBtn.title = s.undo_desc || ''; } if (rBtn) { rBtn.disabled = !s.can_redo; rBtn.title = s.redo_desc || ''; } if (uLabel) { uLabel.textContent = s.undo_desc || ''; } }).catch(function() {}); }; window.doUndo = function() { API.post('/api/undo/undo').then(function(r) { notify(r.message || 'Undo complete', 'success'); updateUndoBar(); if(r.has_duplicates) { window.location = '/'; return; } if(window.refreshPage)refreshPage(); }).catch(function(e) { notify('Undo failed: '+e.message, 'error'); }); }; window.doRedo = function() { API.post('/api/undo/redo').then(function(r) { notify(r.message || 'Redo complete', 'success'); updateUndoBar(); if(r.has_duplicates) { window.location = '/'; return; } if(window.refreshPage)refreshPage(); }).catch(function(e) { notify('Redo failed: '+e.message, 'error'); }); }; window.addEventListener('keydown', function(e) { if ((e.ctrlKey || e.metaKey) && e.key === 'z') { e.preventDefault(); if (e.shiftKey) { doRedo(); } else { doUndo(); } } }); window.saveForm = function(url, data, msg) { API.put(url, data).then(function() { updateUndoBar(); notify(msg || 'Saved', 'success'); }).catch(function(e) { notify('Save failed: '+e.message, 'error'); }); }; document.addEventListener('DOMContentLoaded', function() { updateUndoBar(); });