aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/static/admin.js
blob: a6bb8b2e17b3662f310e3ad4b4178e8bdbd4544d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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'); });
};

window.entityRename = function(type, oldID, newID) {
  return API.post('/api/' + type + '/rename', {id: oldID, new_id: newID}).then(function(r) {
    notify('Renamed ' + oldID + ' to ' + newID, 'success');
    updateUndoBar();
    return r;
  });
};

window.renderRenameableHeader = function(label, id) {
  var h = '<div class="rename-header">';
  h += '<h2 class="rename-header-text">' + esc(label) + ': ' + esc(id) + '</h2>';
  h += '<span class="rename-pencil" onclick="startHeaderRename(this,\'' + escAttr(id) + '\')" title="Rename">\u270E</span>';
  h += '<div class="rename-edit-row" style="display:none"></div>';
  h += '</div>';
  return h;
};

window.handleHeaderRename = function(oldID, newID) {
  var type = window.editorType || '';
  if (!type) return;
  entityRename(type, oldID, newID).then(function() {
    window.currentID = newID;
    var typeSingular = type.slice(0, -1) + 'ID';
    if (window[typeSingular] !== undefined) window[typeSingular] = newID;
    if (window.loadList) window.loadList();
    if (window.loadItem) window.loadItem(newID);
  }).catch(function(e) { notify('Rename failed: ' + e.message, 'error'); });
};

window.startHeaderRename = function(pencilEl, oldID) {
  var header = pencilEl.parentElement;
  var textSpan = header.querySelector('.rename-header-text');
  var editRow = header.querySelector('.rename-edit-row');

  textSpan.style.display = 'none';
  pencilEl.style.display = 'none';
  editRow.style.display = 'flex';
  editRow.innerHTML = '<input class="rename-input" value="' + escAttr(oldID) + '" maxlength="128">' +
    '<button class="btn btn-sm rename-btn-confirm" title="Confirm">\u2713</button>' +
    '<button class="btn btn-sm rename-btn-cancel" title="Cancel">\u2717</button>';

  var input = editRow.querySelector('.rename-input');
  var confirmBtn = editRow.querySelector('.rename-btn-confirm');
  var cancelBtn = editRow.querySelector('.rename-btn-cancel');

  input.focus();
  input.select();

  function cancel() {
    textSpan.style.display = '';
    pencilEl.style.display = '';
    editRow.style.display = 'none';
  }

  function confirm() {
    var newID = input.value.trim();
    if (!newID || newID === oldID) { cancel(); return; }
    if (window.handleHeaderRename) handleHeaderRename(oldID, newID);
  }

  cancelBtn.onclick = cancel;
  input.onkeydown = function(e) { if (e.key === 'Enter') confirm(); else if (e.key === 'Escape') cancel(); };
  confirmBtn.onclick = confirm;
};

document.addEventListener('DOMContentLoaded', function() { updateUndoBar(); });