561 lines
21 KiB
HTML
561 lines
21 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Cargo Filling Editor</title>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body { background: #1a1a2e; color: #e0e0e0; font-family: 'Segoe UI', system-ui, sans-serif; }
|
|
#toolbar {
|
|
position: fixed; top: 0; left: 0; right: 0; z-index: 1000;
|
|
background: #16213e; border-bottom: 1px solid #0f3460;
|
|
display: flex; align-items: center; gap: 12px; padding: 8px 16px; font-size: 14px;
|
|
}
|
|
#toolbar button {
|
|
padding: 6px 14px; border: 1px solid #0f3460; border-radius: 6px;
|
|
background: #1a1a2e; color: #e0e0e0; cursor: pointer; font-size: 13px;
|
|
}
|
|
#toolbar button:hover { background: #0f3460; }
|
|
#toolbar button.primary { background: #533483; border-color: #7b2d8e; }
|
|
#toolbar button.save { background: #1b8a5a; border-color: #239b6e; }
|
|
#page-indicator { color: #a0a0c0; font-weight: 600; min-width: 100px; text-align: center; }
|
|
.spacer { flex: 1; }
|
|
#statusbar {
|
|
position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000;
|
|
background: #16213e; border-top: 1px solid #0f3460;
|
|
padding: 6px 16px; font-size: 12px; color: #a0a0c0;
|
|
}
|
|
#worksheet-container {
|
|
margin-top: 52px; margin-bottom: 32px;
|
|
display: flex; flex-direction: column; align-items: center; gap: 20px; padding: 20px;
|
|
}
|
|
.page-label {
|
|
position: absolute; top: -24px; left: 50%; transform: translateX(-50%);
|
|
background: #533483; color: white; font-size: 11px; font-weight: 700;
|
|
padding: 2px 12px; border-radius: 4px;
|
|
}
|
|
.editor-selected { outline: 3px solid #7c3aed !important; outline-offset: 4px; }
|
|
.editor-changed { position: relative; }
|
|
.editor-changed::after {
|
|
content: ''; position: absolute; top: -2px; right: -2px;
|
|
width: 8px; height: 8px; background: #f97316; border-radius: 50%; z-index: 10;
|
|
}
|
|
#toast {
|
|
position: fixed; bottom: 50px; left: 50%; transform: translateX(-50%);
|
|
background: #533483; color: white; padding: 8px 20px; border-radius: 8px;
|
|
font-size: 13px; font-weight: 600; opacity: 0; transition: opacity 0.3s;
|
|
z-index: 2000; pointer-events: none;
|
|
}
|
|
#toast.show { opacity: 1; }
|
|
#coord-tooltip {
|
|
position: fixed; display: none; background: rgba(0,0,0,0.8); color: #e0e0e0;
|
|
padding: 3px 8px; border-radius: 4px; font-size: 11px; z-index: 2000;
|
|
pointer-events: none; white-space: nowrap;
|
|
}
|
|
.card-inner { overflow: visible !important; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="toolbar">
|
|
<button id="btn-prev">← Prev</button>
|
|
<span id="page-indicator">Page 1 / ?</span>
|
|
<button id="btn-next">Next →</button>
|
|
<div class="spacer"></div>
|
|
<span id="selection-info" style="color: #c4b5fd; font-size: 12px;">Loading...</span>
|
|
<div class="spacer"></div>
|
|
<button id="btn-reset">Reset Page</button>
|
|
<button id="btn-copy" class="primary">Copy JSON</button>
|
|
<button id="btn-copy-changes" class="primary">Copy Changes</button>
|
|
<button id="btn-save" class="save">Save</button>
|
|
</div>
|
|
<div id="worksheet-container"></div>
|
|
<div id="statusbar">
|
|
<span id="status-text">Keys: +/- scale/resize • arrows move • 0 reset • Esc deselect</span>
|
|
</div>
|
|
<div id="toast"></div>
|
|
<div id="coord-tooltip"></div>
|
|
|
|
<script src="../../src/editor/editor-core.js"></script>
|
|
<script>
|
|
(function() {
|
|
'use strict';
|
|
|
|
// Selection modes
|
|
var MODE_ASTEROID = 'asteroid';
|
|
var MODE_SHIP = 'ship';
|
|
var MODE_INNER = 'inner';
|
|
var MODE_BADGE = 'badge';
|
|
|
|
// Default values
|
|
var DEFAULTS = {
|
|
asteroidScale: 1.0,
|
|
ship: { right: -12.5, top: -5, width: 90, height: 42 },
|
|
innerAst: { left: 58, top: 73 },
|
|
badge: { left: 40, top: 39 }
|
|
};
|
|
|
|
var allCards = []; // [{el, spaceAsteroid, spaceAsteroidImg, cargoShip, badge, innerAst, remnantContainer, pageNum, cardIndex}]
|
|
var originals = new Map(); // "pageNum-cardIndex" → {asteroidScale, ship:{...}, innerAst:{...}}
|
|
var selected = null; // {card, mode}
|
|
var mmToPxRatio = 1;
|
|
|
|
function cardKey(card) {
|
|
return card.pageNum + '-' + card.cardIndex;
|
|
}
|
|
|
|
// --- Read current state from DOM ---
|
|
|
|
function getAsteroidScale(card) {
|
|
var t = card.spaceAsteroidImg.style.transform || '';
|
|
var m = t.match(/scale\(([\d.]+)\)/);
|
|
return m ? parseFloat(m[1]) : 1.0;
|
|
}
|
|
|
|
function setAsteroidScale(card, scale) {
|
|
// space-asteroid img
|
|
if (scale === 1.0) {
|
|
card.spaceAsteroidImg.style.transform = '';
|
|
} else {
|
|
card.spaceAsteroidImg.style.transform = 'scale(' + scale + ')';
|
|
}
|
|
// remnant shape container
|
|
if (card.remnantContainer) {
|
|
if (scale === 1.0) {
|
|
card.remnantContainer.style.transform = '';
|
|
} else {
|
|
card.remnantContainer.style.transform = 'scale(' + scale + ')';
|
|
}
|
|
}
|
|
// inner-ast: must compose with translate(-50%,-50%)
|
|
if (card.innerAst) {
|
|
if (scale === 1.0) {
|
|
card.innerAst.style.transform = 'translate(-50%, -50%)';
|
|
} else {
|
|
card.innerAst.style.transform = 'translate(-50%, -50%) scale(' + scale + ')';
|
|
}
|
|
}
|
|
}
|
|
|
|
function getShipValues(card) {
|
|
var cs = card.cargoShip.style;
|
|
return {
|
|
right: parseFloat(cs.right) || DEFAULTS.ship.right,
|
|
top: parseFloat(cs.top) || DEFAULTS.ship.top,
|
|
width: parseFloat(cs.width) || DEFAULTS.ship.width,
|
|
height: parseFloat(cs.height) || DEFAULTS.ship.height
|
|
};
|
|
}
|
|
|
|
function setShipValues(card, vals) {
|
|
card.cargoShip.style.right = vals.right + 'mm';
|
|
card.cargoShip.style.top = vals.top + 'mm';
|
|
card.cargoShip.style.width = vals.width + 'mm';
|
|
card.cargoShip.style.height = vals.height + 'mm';
|
|
}
|
|
|
|
function getInnerAstValues(card) {
|
|
var s = card.innerAst.style;
|
|
var left = parseFloat(s.left);
|
|
var top = parseFloat(s.top);
|
|
// If no inline style, read from computed or defaults
|
|
if (isNaN(left)) left = DEFAULTS.innerAst.left;
|
|
if (isNaN(top)) top = DEFAULTS.innerAst.top;
|
|
return { left: left, top: top };
|
|
}
|
|
|
|
function setInnerAstValues(card, vals) {
|
|
card.innerAst.style.left = vals.left + '%';
|
|
card.innerAst.style.top = vals.top + '%';
|
|
}
|
|
|
|
function getBadgeValues(card) {
|
|
if (!card.badge) return { left: DEFAULTS.badge.left, top: DEFAULTS.badge.top };
|
|
var s = card.badge.style;
|
|
var left = parseFloat(s.left);
|
|
var top = parseFloat(s.top);
|
|
if (isNaN(left)) left = DEFAULTS.badge.left;
|
|
if (isNaN(top)) top = DEFAULTS.badge.top;
|
|
return { left: left, top: top };
|
|
}
|
|
|
|
function setBadgeValues(card, vals) {
|
|
if (!card.badge) return;
|
|
card.badge.style.left = vals.left + '%';
|
|
card.badge.style.top = vals.top + '%';
|
|
}
|
|
|
|
// --- Get full card state ---
|
|
|
|
function getCardState(card) {
|
|
return {
|
|
asteroidScale: getAsteroidScale(card),
|
|
ship: getShipValues(card),
|
|
innerAst: card.innerAst ? getInnerAstValues(card) : { left: DEFAULTS.innerAst.left, top: DEFAULTS.innerAst.top },
|
|
badge: card.badge ? getBadgeValues(card) : { left: DEFAULTS.badge.left, top: DEFAULTS.badge.top }
|
|
};
|
|
}
|
|
|
|
function statesEqual(a, b) {
|
|
if (Math.abs(a.asteroidScale - b.asteroidScale) > 0.001) return false;
|
|
if (Math.abs(a.ship.right - b.ship.right) > 0.01) return false;
|
|
if (Math.abs(a.ship.top - b.ship.top) > 0.01) return false;
|
|
if (Math.abs(a.ship.width - b.ship.width) > 0.01) return false;
|
|
if (Math.abs(a.ship.height - b.ship.height) > 0.01) return false;
|
|
if (Math.abs(a.innerAst.left - b.innerAst.left) > 0.01) return false;
|
|
if (Math.abs(a.innerAst.top - b.innerAst.top) > 0.01) return false;
|
|
if (Math.abs(a.badge.left - b.badge.left) > 0.01) return false;
|
|
if (Math.abs(a.badge.top - b.badge.top) > 0.01) return false;
|
|
return true;
|
|
}
|
|
|
|
// --- Card discovery ---
|
|
|
|
function findCards(pages, mmToPx) {
|
|
mmToPxRatio = mmToPx;
|
|
allCards.length = 0;
|
|
pages.forEach(function(page, pi) {
|
|
var taskCards = page.querySelectorAll('.task-card');
|
|
taskCards.forEach(function(el, ci) {
|
|
var spaceAsteroid = el.querySelector('.space-asteroid');
|
|
var spaceAsteroidImg = spaceAsteroid ? spaceAsteroid.querySelector('img') : null;
|
|
var cargoShip = el.querySelector('.cargo-ship');
|
|
var badge = el.querySelector('.badge-10');
|
|
var innerAst = el.querySelector('.inner-ast');
|
|
var remnantContainer = el.querySelector('.remnant-shape .shape-container');
|
|
|
|
var card = {
|
|
el: el,
|
|
spaceAsteroid: spaceAsteroid,
|
|
spaceAsteroidImg: spaceAsteroidImg,
|
|
cargoShip: cargoShip,
|
|
badge: badge,
|
|
innerAst: innerAst,
|
|
remnantContainer: remnantContainer,
|
|
pageNum: pi + 1,
|
|
cardIndex: ci
|
|
};
|
|
allCards.push(card);
|
|
|
|
// Store initial state as original (will be overridden by applyData)
|
|
originals.set(cardKey(card), {
|
|
asteroidScale: DEFAULTS.asteroidScale,
|
|
ship: Object.assign({}, DEFAULTS.ship),
|
|
innerAst: Object.assign({}, DEFAULTS.innerAst),
|
|
badge: Object.assign({}, DEFAULTS.badge)
|
|
});
|
|
|
|
// Click handlers
|
|
if (spaceAsteroid) {
|
|
spaceAsteroid.style.cursor = 'pointer';
|
|
spaceAsteroid.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
selectCard(card, MODE_ASTEROID);
|
|
});
|
|
}
|
|
if (cargoShip) {
|
|
cargoShip.style.cursor = 'pointer';
|
|
cargoShip.addEventListener('click', function(e) {
|
|
if (e.target.closest('.inner-ast')) return;
|
|
if (e.target.closest('.badge-10')) return;
|
|
e.stopPropagation();
|
|
selectCard(card, MODE_SHIP);
|
|
});
|
|
}
|
|
if (badge) {
|
|
badge.style.cursor = 'pointer';
|
|
badge.style.zIndex = '20';
|
|
badge.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
selectCard(card, MODE_BADGE);
|
|
});
|
|
}
|
|
if (innerAst) {
|
|
innerAst.style.cursor = 'pointer';
|
|
innerAst.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
selectCard(card, MODE_INNER);
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
document.getElementById('status-text').textContent =
|
|
allCards.length + ' cards. Keys: +/- scale/resize \u2022 arrows move \u2022 0 reset \u2022 Esc deselect';
|
|
document.getElementById('selection-info').textContent = 'Click an element to select';
|
|
}
|
|
|
|
// --- Selection ---
|
|
|
|
function selectCard(card, mode) {
|
|
deselectAll();
|
|
selected = { card: card, mode: mode };
|
|
var highlight;
|
|
if (mode === MODE_ASTEROID) highlight = card.spaceAsteroid;
|
|
else if (mode === MODE_SHIP) highlight = card.cargoShip;
|
|
else if (mode === MODE_INNER) highlight = card.innerAst;
|
|
else if (mode === MODE_BADGE) highlight = card.badge;
|
|
if (highlight) highlight.classList.add('editor-selected');
|
|
updateInfo();
|
|
}
|
|
|
|
function deselectAll() {
|
|
if (selected) {
|
|
var card = selected.card;
|
|
if (card.spaceAsteroid) card.spaceAsteroid.classList.remove('editor-selected');
|
|
if (card.cargoShip) card.cargoShip.classList.remove('editor-selected');
|
|
if (card.innerAst) card.innerAst.classList.remove('editor-selected');
|
|
selected = null;
|
|
}
|
|
updateInfo();
|
|
}
|
|
|
|
function updateInfo() {
|
|
var el = document.getElementById('selection-info');
|
|
if (!selected) { el.textContent = 'Click an element to select'; return; }
|
|
var c = selected.card;
|
|
var prefix = 'P' + c.pageNum + ' C' + (c.cardIndex + 1) + ' | ';
|
|
if (selected.mode === MODE_ASTEROID) {
|
|
var s = getAsteroidScale(c);
|
|
el.textContent = prefix + 'Asteroid scale: ' + s.toFixed(2);
|
|
} else if (selected.mode === MODE_SHIP) {
|
|
var v = getShipValues(c);
|
|
el.textContent = prefix + 'Ship R:' + v.right.toFixed(1) + 'mm T:' + v.top.toFixed(1) + 'mm ' + v.width.toFixed(0) + '\u00D7' + v.height.toFixed(0) + 'mm';
|
|
} else if (selected.mode === MODE_INNER) {
|
|
var iv = getInnerAstValues(c);
|
|
el.textContent = prefix + 'Inner L:' + iv.left.toFixed(1) + '% T:' + iv.top.toFixed(1) + '%';
|
|
} else if (selected.mode === MODE_BADGE) {
|
|
var bv = getBadgeValues(c);
|
|
el.textContent = prefix + 'Badge L:' + bv.left.toFixed(1) + '% T:' + bv.top.toFixed(1) + '%';
|
|
}
|
|
}
|
|
|
|
// --- Change tracking ---
|
|
|
|
function markChanged(card) {
|
|
var orig = originals.get(cardKey(card));
|
|
var cur = getCardState(card);
|
|
var changed = !statesEqual(cur, orig);
|
|
card.el.classList.toggle('editor-changed', changed);
|
|
}
|
|
|
|
// --- Apply data.json to DOM ---
|
|
|
|
function applyData(data) {
|
|
if (!data || !data.pages) return;
|
|
var count = 0;
|
|
data.pages.forEach(function(p) {
|
|
(p.cards || []).forEach(function(cd) {
|
|
var card = allCards.find(function(c) {
|
|
return c.pageNum === p.page && c.cardIndex === cd.index;
|
|
});
|
|
if (!card) return;
|
|
|
|
var scale = cd.asteroidScale != null ? cd.asteroidScale : DEFAULTS.asteroidScale;
|
|
if (cd.asteroidScale != null) {
|
|
setAsteroidScale(card, scale);
|
|
}
|
|
|
|
if (cd.ship) {
|
|
var sv = {
|
|
right: cd.ship.right != null ? cd.ship.right : DEFAULTS.ship.right,
|
|
top: cd.ship.top != null ? cd.ship.top : DEFAULTS.ship.top,
|
|
width: cd.ship.width != null ? cd.ship.width : DEFAULTS.ship.width,
|
|
height: cd.ship.height != null ? cd.ship.height : DEFAULTS.ship.height
|
|
};
|
|
setShipValues(card, sv);
|
|
}
|
|
|
|
if (cd.innerAst && card.innerAst) {
|
|
var iv = {
|
|
left: cd.innerAst.left != null ? cd.innerAst.left : DEFAULTS.innerAst.left,
|
|
top: cd.innerAst.top != null ? cd.innerAst.top : DEFAULTS.innerAst.top
|
|
};
|
|
setInnerAstValues(card, iv);
|
|
}
|
|
|
|
// Update originals to saved state
|
|
originals.set(cardKey(card), getCardState(card));
|
|
card.el.classList.remove('editor-changed');
|
|
count++;
|
|
});
|
|
});
|
|
if (count > 0) core.showToast('Loaded ' + count + ' card edits');
|
|
}
|
|
|
|
// --- Serialization ---
|
|
|
|
function buildConfig(changesOnly) {
|
|
var pagesMap = {};
|
|
allCards.forEach(function(card) {
|
|
var cur = getCardState(card);
|
|
var orig = originals.get(cardKey(card));
|
|
|
|
var cardData = { index: card.cardIndex };
|
|
var hasChange = false;
|
|
|
|
// Asteroid scale
|
|
if (Math.abs(cur.asteroidScale - DEFAULTS.asteroidScale) > 0.001) {
|
|
if (!changesOnly || Math.abs(cur.asteroidScale - orig.asteroidScale) > 0.001) {
|
|
cardData.asteroidScale = +cur.asteroidScale.toFixed(3);
|
|
hasChange = true;
|
|
}
|
|
} else if (!changesOnly) {
|
|
// At default, skip
|
|
}
|
|
|
|
// Ship
|
|
var shipChanged = false;
|
|
var shipData = {};
|
|
if (Math.abs(cur.ship.right - DEFAULTS.ship.right) > 0.01) { shipData.right = +cur.ship.right.toFixed(1); shipChanged = true; }
|
|
if (Math.abs(cur.ship.top - DEFAULTS.ship.top) > 0.01) { shipData.top = +cur.ship.top.toFixed(1); shipChanged = true; }
|
|
if (Math.abs(cur.ship.width - DEFAULTS.ship.width) > 0.01) { shipData.width = +cur.ship.width.toFixed(1); shipChanged = true; }
|
|
if (Math.abs(cur.ship.height - DEFAULTS.ship.height) > 0.01) { shipData.height = +cur.ship.height.toFixed(1); shipChanged = true; }
|
|
if (shipChanged) {
|
|
if (!changesOnly || !statesEqual(cur, orig)) {
|
|
cardData.ship = shipData;
|
|
hasChange = true;
|
|
}
|
|
}
|
|
|
|
// Inner asteroid
|
|
if (card.innerAst) {
|
|
var innerChanged = false;
|
|
var innerData = {};
|
|
if (Math.abs(cur.innerAst.left - DEFAULTS.innerAst.left) > 0.01) { innerData.left = +cur.innerAst.left.toFixed(1); innerChanged = true; }
|
|
if (Math.abs(cur.innerAst.top - DEFAULTS.innerAst.top) > 0.01) { innerData.top = +cur.innerAst.top.toFixed(1); innerChanged = true; }
|
|
if (innerChanged) {
|
|
if (!changesOnly || Math.abs(cur.innerAst.left - orig.innerAst.left) > 0.01 || Math.abs(cur.innerAst.top - orig.innerAst.top) > 0.01) {
|
|
cardData.innerAst = innerData;
|
|
hasChange = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (changesOnly && !hasChange) return;
|
|
if (!changesOnly && !hasChange) return;
|
|
|
|
if (!pagesMap[card.pageNum]) pagesMap[card.pageNum] = { page: card.pageNum, cards: [] };
|
|
pagesMap[card.pageNum].cards.push(cardData);
|
|
});
|
|
return { pages: Object.values(pagesMap) };
|
|
}
|
|
|
|
// --- Reset ---
|
|
|
|
function resetCurrentPage(pageNum) {
|
|
allCards.forEach(function(card) {
|
|
if (card.pageNum !== pageNum) return;
|
|
var orig = originals.get(cardKey(card));
|
|
setAsteroidScale(card, orig.asteroidScale);
|
|
setShipValues(card, orig.ship);
|
|
if (card.innerAst) setInnerAstValues(card, orig.innerAst);
|
|
card.el.classList.remove('editor-changed');
|
|
});
|
|
if (selected && selected.card.pageNum === pageNum) updateInfo();
|
|
}
|
|
|
|
// --- Keyboard ---
|
|
|
|
function setupKeyboard() {
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape') { deselectAll(); return; }
|
|
if (!selected) return;
|
|
|
|
var card = selected.card;
|
|
var mode = selected.mode;
|
|
|
|
if (mode === MODE_ASTEROID) {
|
|
var scale = getAsteroidScale(card);
|
|
var step = e.shiftKey ? 0.01 : 0.05;
|
|
switch (e.key) {
|
|
case '+': case '=':
|
|
setAsteroidScale(card, Math.min(2, +(scale + step).toFixed(3)));
|
|
markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case '-': case '_':
|
|
setAsteroidScale(card, Math.max(0.3, +(scale - step).toFixed(3)));
|
|
markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case '0':
|
|
setAsteroidScale(card, DEFAULTS.asteroidScale);
|
|
markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
}
|
|
} else if (mode === MODE_SHIP) {
|
|
var sv = getShipValues(card);
|
|
var moveStep = e.shiftKey ? 0.5 : 2;
|
|
var sizeStep = e.shiftKey ? 1 : 2;
|
|
switch (e.key) {
|
|
case 'ArrowLeft':
|
|
sv.right = +(sv.right + moveStep).toFixed(1); // left = increase right
|
|
setShipValues(card, sv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case 'ArrowRight':
|
|
sv.right = +(sv.right - moveStep).toFixed(1); // right = decrease right
|
|
setShipValues(card, sv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case 'ArrowUp':
|
|
sv.top = +(sv.top - moveStep).toFixed(1);
|
|
setShipValues(card, sv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case 'ArrowDown':
|
|
sv.top = +(sv.top + moveStep).toFixed(1);
|
|
setShipValues(card, sv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case '+': case '=':
|
|
sv.width = +(sv.width + sizeStep).toFixed(1);
|
|
sv.height = +(sv.height + sizeStep * (DEFAULTS.ship.height / DEFAULTS.ship.width)).toFixed(1);
|
|
setShipValues(card, sv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case '-': case '_':
|
|
sv.width = Math.max(20, +(sv.width - sizeStep).toFixed(1));
|
|
sv.height = Math.max(10, +(sv.height - sizeStep * (DEFAULTS.ship.height / DEFAULTS.ship.width)).toFixed(1));
|
|
setShipValues(card, sv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case '0':
|
|
setShipValues(card, Object.assign({}, DEFAULTS.ship));
|
|
markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
}
|
|
} else if (mode === MODE_INNER) {
|
|
var iv = getInnerAstValues(card);
|
|
var pctStep = e.shiftKey ? 0.5 : 1;
|
|
switch (e.key) {
|
|
case 'ArrowLeft':
|
|
iv.left = +(iv.left - pctStep).toFixed(1);
|
|
setInnerAstValues(card, iv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case 'ArrowRight':
|
|
iv.left = +(iv.left + pctStep).toFixed(1);
|
|
setInnerAstValues(card, iv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case 'ArrowUp':
|
|
iv.top = +(iv.top - pctStep).toFixed(1);
|
|
setInnerAstValues(card, iv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case 'ArrowDown':
|
|
iv.top = +(iv.top + pctStep).toFixed(1);
|
|
setInnerAstValues(card, iv); markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
case '0':
|
|
setInnerAstValues(card, Object.assign({}, DEFAULTS.innerAst));
|
|
// Also reset transform to just translate (remove scale if any)
|
|
card.innerAst.style.transform = 'translate(-50%, -50%)';
|
|
markChanged(card); updateInfo(); e.preventDefault(); break;
|
|
}
|
|
}
|
|
});
|
|
|
|
document.addEventListener('click', function(e) {
|
|
if (selected && !e.target.closest('.space-asteroid') && !e.target.closest('.cargo-ship') && !e.target.closest('.inner-ast')) {
|
|
deselectAll();
|
|
}
|
|
});
|
|
}
|
|
|
|
// --- Init via EditorCore ---
|
|
|
|
var core = EditorCore.init({
|
|
taskType: 'cargo-filling',
|
|
serialize: buildConfig,
|
|
onReset: resetCurrentPage,
|
|
onReady: function(pages, mmToPx) {
|
|
findCards(pages, mmToPx);
|
|
setupKeyboard();
|
|
},
|
|
onDataLoaded: function(data) {
|
|
if (data) applyData(data);
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|