aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/static
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-30 04:43:54 -0400
committerhistoria <[not public]>2026-06-30 04:43:54 -0400
commit98bdef072c843fdd8ccdf85a9b54ab9d32d34187 (patch)
treed4c5c4955ba8e02e895ae0713a2c3439bc93868a /internal/admin/static
parent712072209ab5e3b3a14ebc0c770b020afe544560 (diff)
downloadthehouseoficarus-98bdef072c843fdd8ccdf85a9b54ab9d32d34187.tar.gz
slop refactor
Diffstat (limited to 'internal/admin/static')
-rw-r--r--internal/admin/static/map.js184
1 files changed, 100 insertions, 84 deletions
diff --git a/internal/admin/static/map.js b/internal/admin/static/map.js
index cd53bed..85364d5 100644
--- a/internal/admin/static/map.js
+++ b/internal/admin/static/map.js
@@ -47,7 +47,7 @@ function loadMap() {
if (currentDir) url += '&dir=' + encodeURIComponent(currentDir);
var wasDirChange = dirChangedByUser;
dirChangedByUser = false;
- API.get(url).then(function(data) {
+ return API.get(url).then(function(data) {
mapData = data;
if (!currentDir && data.dir) {
currentDir = data.dir;
@@ -64,11 +64,11 @@ function loadMap() {
}
function blendColors(colorA, colorB) {
+ if (!colorA && !colorB) return '#666666';
+ if (!colorB) return xtermToCss(parseXtermIdx(colorA));
+ if (!colorA) return xtermToCss(parseXtermIdx(colorB));
var idxA = parseXtermIdx(colorA);
var idxB = parseXtermIdx(colorB);
- if (colorA && !colorB) return xtermToCss(idxA);
- if (!colorA && colorB) return xtermToCss(idxB);
- if (!colorA && !colorB) return '#666666';
var rgbA = xtermToRGB(idxA);
var rgbB = xtermToRGB(idxB);
var r = Math.round((rgbA[0] + rgbB[0]) / 2);
@@ -90,17 +90,21 @@ function renderMap(data) {
var W = container.clientWidth;
var H = container.clientHeight;
- roomMap = {};
- if (data.rooms) data.rooms.forEach(function(r) { roomMap[r.id] = r; });
-
- occupied = {};
- if (data.rooms) data.rooms.forEach(function(r) { occupied[r.x+','+r.y] = r.id; });
-
+ roomMap = {}; occupied = {};
upTarget = {}; downTarget = {};
- if (data.upLinks) data.upLinks.forEach(function(l) { upTarget[l.from] = l.to; });
- if (data.downLinks) data.downLinks.forEach(function(l) { downTarget[l.from] = l.to; });
+ var hasUp = {}, hasDown = {};
+
+ if (data.rooms) data.rooms.forEach(function(r) {
+ roomMap[r.id] = r;
+ occupied[r.x+','+r.y] = r.id;
+ });
+ if (data.upLinks) data.upLinks.forEach(function(l) {
+ upTarget[l.from] = l.to; hasUp[l.from] = true;
+ });
+ if (data.downLinks) data.downLinks.forEach(function(l) {
+ downTarget[l.from] = l.to; hasDown[l.from] = true;
+ });
- var svgNS = 'http://www.w3.org/2000/svg';
var g = '';
if (data.links) {
@@ -109,16 +113,11 @@ function renderMap(data) {
if (!fr || !tr) return;
var x1 = fr.x * CELL + CELL/2, y1 = fr.y * CELL + CELL/2;
var x2 = tr.x * CELL + CELL/2, y2 = tr.y * CELL + CELL/2;
- var c = blendColors(fr.color, tr.color);
- c = c.replace('#','');
+ var c = blendColors(fr.color, tr.color).replace('#','');
g += '<line x1="'+x1+'" y1="'+y1+'" x2="'+x2+'" y2="'+y2+'" stroke="#'+c+'" stroke-width="6" opacity="0.55"'+ (l.bidirectional ? '' : ' stroke-dasharray="4,3"')+' vector-effect="non-scaling-stroke"/>';
});
}
- var hasUp = {}, hasDown = {};
- if (data.upLinks) data.upLinks.forEach(function(l) { hasUp[l.from] = true; });
- if (data.downLinks) data.downLinks.forEach(function(l) { hasDown[l.from] = true; });
-
var roomHTML = '';
if (data.rooms) {
data.rooms.forEach(function(r) {
@@ -126,7 +125,7 @@ function renderMap(data) {
var fill = resolveColor(r.color);
var txtColor = hexLuminance(fill) > 0.35 ? '#111' : '#fff';
var sel = selectedRoom === r.id;
- roomHTML += '<rect class="rm" x="'+x+'" y="'+y+'" width="'+w+'" height="'+h+'" rx="5" fill="'+fill+'" stroke="'+(sel?'#fff':fill)+'" stroke-width="'+(sel?3:1.5)+'" data-id="'+r.id+'" data-name="'+esc(r.name)+'"/>';
+ roomHTML += '<rect class="rm" x="'+x+'" y="'+y+'" width="'+w+'" height="'+h+'" rx="5" fill="'+fill+'" stroke="'+(sel?'#fff':fill)+'" stroke-width="'+(sel?3:1.5)+'" data-id="'+r.id+'"/>';
var dimColor = hexLuminance(fill) > 0.35 ? 'rgba(0,0,0,0.45)' : 'rgba(255,255,255,0.4)';
roomHTML += '<text x="'+(x+w/2)+'" y="'+(y+14)+'" text-anchor="middle" font-size="8" fill="'+dimColor+'" font-family="monospace" pointer-events="none">#'+r.id+'</text>';
@@ -167,7 +166,7 @@ function renderMap(data) {
svg.setAttribute('height', H);
svg.innerHTML = '<g>' + innerHTML + '</g>';
- svg.addEventListener('contextmenu', function(e) { e.preventDefault(); });
+ svg.oncontextmenu = function(e) { e.preventDefault(); };
svg.onmousedown = function(e) {
var onRoom = e.target.classList.contains('rm');
@@ -180,9 +179,7 @@ function renderMap(data) {
var dz = parseInt(e.target.getAttribute('data-dz'));
var tid = parseInt(e.target.getAttribute('data-target'));
currentZ += dz;
- selectedRoom = tid;
- loadMap();
- selectRoom(tid);
+ loadMap().then(function() { selectRoom(tid); });
return;
}
@@ -292,7 +289,6 @@ function renderMap(data) {
if (scale > 5) scale = 5;
updateView();
};
-
}
function wrapText(name, cx, cy, maxWidth, color) {
@@ -338,8 +334,24 @@ function updateView() {
function selectRoom(id) {
if (saveTimer) { clearTimeout(saveTimer); saveTimer = null; }
+ var prev = selectedRoom;
selectedRoom = id;
- loadMap();
+
+ if (mapData && roomMap) {
+ if (prev && prev !== id) {
+ var prevEl = document.querySelector('.rm[data-id="'+prev+'"]');
+ if (prevEl) {
+ prevEl.setAttribute('stroke', prevEl.getAttribute('fill') || '#3a3a6a');
+ prevEl.setAttribute('stroke-width', '1.5');
+ }
+ }
+ var el = document.querySelector('.rm[data-id="'+id+'"]');
+ if (el) {
+ el.setAttribute('stroke', '#fff');
+ el.setAttribute('stroke-width', '3');
+ }
+ }
+
API.get('/api/rooms/' + id).then(function(data) {
renderSidePanel(data);
}).catch(function(e) {
@@ -443,9 +455,7 @@ function renderHazardTab(r) {
}
function searchHazards(input) {
- searchAndShow(input, 'hazards', function(r) {
- addHazard(r.id);
- });
+ searchAndShow(input, 'hazards', function(r) { addHazard(r.id); });
}
function addHazard(id) {
if (!currentRoomData || !currentRoomData.room) return;
@@ -597,7 +607,6 @@ function renderItemsTab(spawns) {
function renderExitsSection(r) {
var exits = r.exits || {};
var exitDirs = ['north','south','east','west','northeast','northwest','southeast','southwest','up','down'];
- var dirAliases = {n:'north',s:'south',e:'east',w:'west',ne:'northeast',nw:'northwest',se:'southeast',sw:'southwest',u:'up',d:'down'};
var h = '<div class="exit-section"><h3>Exits</h3>';
exitDirs.forEach(function(d) {
var exit = exits[d];
@@ -676,7 +685,6 @@ function editExitCondition(dir) {
menu._condClauses = parsed.clauses;
menu._condMode = parsed.mode;
- // Fix: mode is always 'all' for our editor, but store what was parsed
renderConditionClauses(menu);
}
@@ -801,7 +809,6 @@ function saveExitCondition() {
exit.set_flags = parseFlagInput(flagsStr ? flagsStr.value : '');
exit.set_player_flags = parseFlagInput(pflagsStr ? pflagsStr.value : '');
- // Update clause data from DOM before saving
var clauseEls = menu.querySelectorAll('.cond-clause');
clauseEls.forEach(function(el) { updateClauseData(el); });
@@ -868,8 +875,7 @@ function addExit() {
API.post('/api/rooms/link', {from: selectedRoom, to: target, dir: dir}).then(function() {
notify('Exit added: ' + dir + ' #' + target, 'success');
updateUndoBar();
- loadMap();
- selectRoom(selectedRoom);
+ loadMap().then(function() { selectRoom(selectedRoom); });
}).catch(function(e) { notify('Add exit failed: ' + extractError(e), 'error'); });
}
@@ -887,8 +893,7 @@ function deleteExit(dir, target) {
}).then(function() {
notify('Removed exit ' + dir + ' to #' + target, 'success');
updateUndoBar();
- loadMap();
- selectRoom(selectedRoom);
+ loadMap().then(function() { selectRoom(selectedRoom); });
}).catch(function(e) { notify('Delete exit failed: ' + extractError(e), 'error'); });
}
@@ -997,9 +1002,7 @@ function addRefObject(id) {
}
function searchRefObjects(input) {
- searchAndShow(input, 'objects', function(r) {
- addRefObject(r.id);
- });
+ searchAndShow(input, 'objects', function(r) { addRefObject(r.id); });
}
function removeSpawn(i) {
@@ -1029,9 +1032,7 @@ function addSpawn(id) {
}
function searchItemSpawns(input) {
- searchAndShow(input, 'items', function(r) {
- addSpawn(r.id);
- });
+ searchAndShow(input, 'items', function(r) { addSpawn(r.id); });
}
function removeMob(i) {
@@ -1049,9 +1050,7 @@ function addMob(id) {
}
function searchMobs(input) {
- searchAndShow(input, 'mobs', function(r) {
- addMob(r.id);
- });
+ searchAndShow(input, 'mobs', function(r) { addMob(r.id); });
}
function searchAndShow(input, type, onSelect) {
@@ -1112,20 +1111,14 @@ function saveNow() {
doSavePanel();
}
-function doSavePanel() {
+async function doSavePanel() {
var id = selectedRoom;
if (!id) return;
- var save = function(r) {
- API.put('/api/rooms/' + id, r).then(function() {
- notify('Room #' + id + ' saved', 'success');
- updateUndoBar();
- loadMap();
- }).catch(function(e) { notify('Save failed: '+e.message, 'error'); });
- };
-
- API.get('/api/rooms/' + id).then(function(data) {
+ try {
+ var data = await API.get('/api/rooms/' + id);
var r = data.room || {};
r.id = id;
+
var el = $('#roomName'); if (el) r.name = el.value;
el = $('#roomColor'); if (el) r.color = el.value;
el = $('#roomDesc'); if (el && el.value) r.description = [{text: el.value}];
@@ -1140,29 +1133,29 @@ function doSavePanel() {
if (r.block_transport === undefined) r.block_transport = currentRoomData.room.block_transport;
}
- var el = $('#roomID'); var newID = el ? parseInt(el.value) || id : id;
+ el = $('#roomID');
+ var newID = el ? parseInt(el.value) || id : id;
var dirEl = $('#roomDir');
var newDir = dirEl ? dirEl.value : null;
var currentDir = (data.file || '').replace(/^data\/rooms\/?/, '').split('/')[0] || '';
if (dirEl && newDir !== currentDir) {
- API.post('/api/rooms/move', {id: id, dir: newDir}).then(function() {
- if (newID !== id) {
- API.post('/api/rooms/rename', {id: id, new_id: newID}).then(function() {
- selectRoom(newID);
- }).catch(function(e) { notify('Rename failed: '+e.message, 'error'); save(r); });
- } else { save(r); }
- }).catch(function(e) { notify('Move failed: '+e.message, 'error'); save(r); });
- } else if (newID !== id) {
- API.post('/api/rooms/rename', {id: id, new_id: newID}).then(function() {
- selectRoom(newID);
- }).catch(function(e) {
- notify('Rename failed: '+e.message, 'error');
- var rid = $('#roomID'); if (rid) rid.value = id;
- save(r);
- });
- } else { save(r); }
- }).catch(function(e) { notify('Save failed: '+e.message, 'error'); });
+ await API.post('/api/rooms/move', {id: id, dir: newDir});
+ }
+ if (newID !== id) {
+ await API.post('/api/rooms/rename', {id: id, new_id: newID});
+ selectedRoom = newID;
+ id = newID;
+ }
+
+ await API.put('/api/rooms/' + id, r);
+ notify('Room #' + id + ' saved', 'success');
+ updateUndoBar();
+ await loadMap();
+ selectRoom(id);
+ } catch (e) {
+ notify('Save failed: ' + extractError(e), 'error');
+ }
}
function deleteRoom(id) {
@@ -1175,6 +1168,18 @@ function deleteRoom(id) {
if (l.to === id && l.from !== id) neighbors.push(l.from);
});
}
+ if (mapData.upLinks) {
+ mapData.upLinks.forEach(function(l) {
+ if (l.from === id && l.to !== id) neighbors.push(l.to);
+ if (l.to === id && l.from !== id) neighbors.push(l.from);
+ });
+ }
+ if (mapData.downLinks) {
+ mapData.downLinks.forEach(function(l) {
+ if (l.from === id && l.to !== id) neighbors.push(l.to);
+ if (l.to === id && l.from !== id) neighbors.push(l.from);
+ });
+ }
if (neighbors.length > 1) {
var remaining = mapData.rooms.filter(function(r) { return r.id !== id; });
var adj = {};
@@ -1186,6 +1191,20 @@ function deleteRoom(id) {
if (adj[l.to]) adj[l.to].push(l.from);
});
}
+ if (mapData.upLinks) {
+ mapData.upLinks.forEach(function(l) {
+ if (l.from === id || l.to === id) return;
+ if (adj[l.from]) adj[l.from].push(l.to);
+ if (adj[l.to]) adj[l.to].push(l.from);
+ });
+ }
+ if (mapData.downLinks) {
+ mapData.downLinks.forEach(function(l) {
+ if (l.from === id || l.to === id) return;
+ if (adj[l.from]) adj[l.from].push(l.to);
+ if (adj[l.to]) adj[l.to].push(l.from);
+ });
+ }
if (remaining.length > 0) {
var visited = {}, queue = [remaining[0].id];
visited[remaining[0].id] = true;
@@ -1219,7 +1238,7 @@ function createRoom(fromID, dir) {
var createdId = (resp && resp.room && resp.room.id) || newID;
notify('Room #' + createdId + ' created', 'success');
updateUndoBar();
- selectRoom(createdId);
+ loadMap().then(function() { selectRoom(createdId); });
}).catch(function(e) { notify('Create failed: ' + e.message, 'error'); });
});
}
@@ -1323,7 +1342,7 @@ function applyGhostLinkHighlight(fromRoom, gx, gy) {
fromEl.setAttribute('stroke', '#0ff');
fromEl.setAttribute('stroke-width', '3');
- var g = document.querySelector('#mapSvg g');
+ var g = document.querySelector('#mapSvg g');
if (!g) return;
var svgNS = 'http://www.w3.org/2000/svg';
var line = document.createElementNS(svgNS, 'line');
@@ -1353,7 +1372,7 @@ function applyLinkHighlight(fromId, toId) {
toEl.setAttribute('stroke', '#f0f');
toEl.setAttribute('stroke-width', '3');
- var g = document.querySelector('#mapSvg g');
+ var g = document.querySelector('#mapSvg g');
if (!g) return;
var svgNS = 'http://www.w3.org/2000/svg';
var line = document.createElementNS(svgNS, 'line');
@@ -1393,12 +1412,9 @@ function createLink(fromId, toId) {
API.post('/api/rooms/link', {from: fromId, to: toId}).then(function() {
notify('Linked rooms #'+fromId+' '+toId, 'success');
updateUndoBar();
- loadMap();
- if (selectedRoom) {
- API.get('/api/rooms/' + selectedRoom).then(function(data) {
- renderSidePanel(data);
- });
- }
+ loadMap().then(function() {
+ if (selectedRoom) selectRoom(selectedRoom);
+ });
}).catch(function(e) {
notify('Link failed: ' + e.message, 'error');
});
@@ -1441,7 +1457,7 @@ function applyDelHighlight(fromId, toId) {
toEl.setAttribute('stroke', '#f55');
toEl.setAttribute('stroke-width', '3');
- var g = document.querySelector('#mapSvg g');
+ var g = document.querySelector('#mapSvg g');
if (!g) return;
var svgNS = 'http://www.w3.org/2000/svg';
var line = document.createElementNS(svgNS, 'line');
@@ -1587,7 +1603,7 @@ function escAttr(s) {
return String(s).replace(/&/g,'&amp;').replace(/"/g,'&quot;');
}
-window.refreshPage = function() { loadMap(); if (selectedRoom) selectRoom(selectedRoom); };
+window.refreshPage = function() { loadMap().then(function() { if (selectedRoom) selectRoom(selectedRoom); }); };
function loadRoomDirs(cb) {
API.get('/api/room-dirs').then(function(dirs) {