aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/static/admin.js
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-29 22:31:11 -0400
committerhistoria <[not public]>2026-06-29 22:31:11 -0400
commit069d3c1c81d71042706372df153254487a765dfc (patch)
treed83a4a3954d2b8304f49d83e365f4c2b075b91eb /internal/admin/static/admin.js
parent6c5271fb085b4571a10f106391974c249cd84317 (diff)
downloadthehouseoficarus-069d3c1c81d71042706372df153254487a765dfc.tar.gz
feat: wip web admin for mapping and crud
Diffstat (limited to 'internal/admin/static/admin.js')
-rw-r--r--internal/admin/static/admin.js55
1 files changed, 55 insertions, 0 deletions
diff --git a/internal/admin/static/admin.js b/internal/admin/static/admin.js
new file mode 100644
index 0000000..cce3bc9
--- /dev/null
+++ b/internal/admin/static/admin.js
@@ -0,0 +1,55 @@
+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(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(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(); });