ui: clear stale RAM status on op change, remember the card preset
- ramOpChanged() now clears the previous execution status (result line, steps, explorer, progress) only when the Operation value actually changes, so switching Explore -> Install Package no longer shows the old 'Partial - ELF Modules: no data' until Execute; re-entering the RAM subtab still preserves the last result - ramClearResults() also hides the progress caption - the Card preset dropdown no longer resets to the placeholder after every executed operation (ramSaveCntr -> ramRender rebuilt it) or on subtab re-entry: ramRender keeps the current/remembered index, ramApplyCard and ramExecute remember the selection for the session, and cardsRemove keeps _ramCardIdx aligned via ramCardIdxAfterRemove - tests: op-change clearing, selection preservation across rebuilds, pick/execute remembering, index bookkeeping; SW cache v126 -> v127.
This commit is contained in:
+22
-6
@@ -4806,10 +4806,16 @@ async function pysimSendOta() {
|
||||
// reuse /api/send-ota. Install Package sends the .cap hex to /api/ram-install
|
||||
// which orchestrates INSTALL[for load] -> LOAD x N -> INSTALL[for install].
|
||||
|
||||
let _ramCardIdx = null;
|
||||
let _ramOpLast = null;
|
||||
|
||||
function ramRender() {
|
||||
// populate the card preset selector from the in-memory cards[] array
|
||||
// populate the card preset selector from the in-memory cards[] array,
|
||||
// keeping the current/remembered selection across rebuilds
|
||||
const sel = document.getElementById('ram-card-sel');
|
||||
if (!sel) return;
|
||||
const prev = parseInt(sel.value, 10);
|
||||
const keep = (!isNaN(prev) && cards[prev]) ? prev : _ramCardIdx;
|
||||
sel.innerHTML = '<option value="" data-l10n="— Select card —">— Select card —</option>';
|
||||
cards.forEach((c, i) => {
|
||||
const opt = document.createElement('option');
|
||||
@@ -4817,23 +4823,23 @@ function ramRender() {
|
||||
opt.textContent = c.name || ('Card ' + i);
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
if (keep !== null && keep !== undefined && cards[keep]) sel.value = String(keep);
|
||||
ramOpChanged();
|
||||
}
|
||||
|
||||
function ramApplyCard(idx) {
|
||||
// copy the selected card preset into the SP form fields so that
|
||||
// getRamSpParams() picks up the right SPI/KIc/KID/TAR/CNTR/keys
|
||||
const i = parseInt(idx, 10);
|
||||
if (!isNaN(i) && cards[i]) _ramCardIdx = i;
|
||||
cardsApply(idx);
|
||||
}
|
||||
|
||||
function ramOpChanged() {
|
||||
const op = document.getElementById('ram-op').value;
|
||||
if (_ramOpLast !== null && op !== _ramOpLast) ramClearResults();
|
||||
_ramOpLast = op;
|
||||
document.getElementById('ram-install-params').classList.toggle('hidden', op !== 'install-cap');
|
||||
if (op !== 'explore') {
|
||||
_ramExplorerData = null;
|
||||
document.getElementById('ram-explorer').classList.add('hidden');
|
||||
document.getElementById('ram-explorer').innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
function ramShowProgress(text) {
|
||||
@@ -4848,6 +4854,7 @@ function ramHideProgress() {
|
||||
|
||||
function ramClearResults() {
|
||||
_ramExplorerData = null;
|
||||
ramHideProgress();
|
||||
document.getElementById('ram-result').classList.add('hidden');
|
||||
document.getElementById('ram-explorer').classList.add('hidden');
|
||||
document.getElementById('ram-explorer').innerHTML = '';
|
||||
@@ -5384,6 +5391,8 @@ async function ramInstallCap(sp) {
|
||||
|
||||
async function ramExecute() {
|
||||
ramClearResults();
|
||||
const cardIdx = parseInt(document.getElementById('ram-card-sel').value, 10);
|
||||
if (!isNaN(cardIdx) && cards[cardIdx]) _ramCardIdx = cardIdx;
|
||||
const op = document.getElementById('ram-op').value;
|
||||
const sp = getRamSpParams();
|
||||
if (!sp.kicKey || !sp.kidKey) {
|
||||
@@ -5589,7 +5598,14 @@ function cardsAdd() {
|
||||
});
|
||||
}
|
||||
|
||||
function ramCardIdxAfterRemove(idx, removedIdx) {
|
||||
if (idx === null || idx === undefined || idx < 0) return null;
|
||||
if (idx === removedIdx) return null;
|
||||
return idx > removedIdx ? idx - 1 : idx;
|
||||
}
|
||||
|
||||
function cardsRemove(i) {
|
||||
_ramCardIdx = ramCardIdxAfterRemove(_ramCardIdx, i);
|
||||
cards.splice(i, 1);
|
||||
cardsSave();
|
||||
cardsRender();
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
const CACHE = 'otaman-v126';
|
||||
const CACHE = 'otaman-v127';
|
||||
const URLS = [
|
||||
'index.html',
|
||||
'help.html',
|
||||
|
||||
+125
-2
@@ -6,7 +6,7 @@ const path = require('node:path');
|
||||
const html = fs.readFileSync(path.join(__dirname, '..', 'index.html'), 'utf8');
|
||||
|
||||
function extractFunc(src, name) {
|
||||
const re = new RegExp('function\\s+' + name + '\\s*\\([^)]*\\)\\s*\\{');
|
||||
const re = new RegExp('(?:async\\s+)?function\\s+' + name + '\\s*\\([^)]*\\)\\s*\\{');
|
||||
const m = re.exec(src);
|
||||
if (!m) throw new Error('function ' + name + ' not found');
|
||||
let i = m.index + m[0].length - 1;
|
||||
@@ -22,7 +22,8 @@ function extractFunc(src, name) {
|
||||
}
|
||||
|
||||
// Extract chain builder functions and dependencies
|
||||
const FNS = ['berLenStr', 'buildApdu', 'escHtml', 'esc', 'chainInit', 'chainRamBuildRowHex', 'ramFmtLifecycle', 'ramFmtPrivileges', 'ramRenderExploreHtml'];
|
||||
const FNS = ['berLenStr', 'buildApdu', 'escHtml', 'esc', 'chainInit', 'chainRamBuildRowHex', 'ramFmtLifecycle', 'ramFmtPrivileges', 'ramRenderExploreHtml',
|
||||
'ramCardIdxAfterRemove', 'ramClearResults', 'ramHideProgress', 'ramOpChanged', 'ramRender', 'ramApplyCard', 'ramExecute'];
|
||||
let code = '';
|
||||
for (const f of FNS) {
|
||||
code += extractFunc(html, f) + '\n';
|
||||
@@ -32,6 +33,8 @@ if (m) code += m[0].replace(/^const /, 'var ') + '\n';
|
||||
const lc = html.match(/const RAM_LIFECYCLE = \{[\s\S]*?\n\};/);
|
||||
if (lc) code += lc[0].replace(/^const /, 'var ') + '\n';
|
||||
eval(code);
|
||||
code += 'var _ramCardIdx = null;\nvar _ramOpLast = null;\nvar _ramExplorerData = null;\n';
|
||||
eval(code);
|
||||
|
||||
const els = {};
|
||||
const doc = { getElementById: (id) => { if (!els[id]) els[id] = {value:''}; return els[id]; } };
|
||||
@@ -197,3 +200,123 @@ test('ramFmtPrivileges uses the translated (none) placeholder', () => {
|
||||
assert.strictEqual(ramFmtPrivileges('00'), 'XX(none)');
|
||||
delete global.t;
|
||||
});
|
||||
|
||||
function fakeClassList() {
|
||||
const set = new Set();
|
||||
return {
|
||||
add: (...cs) => cs.forEach(c => set.add(c)),
|
||||
remove: (...cs) => cs.forEach(c => set.delete(c)),
|
||||
contains: c => set.has(c),
|
||||
toggle: (c, on) => { if (on === undefined ? !set.has(c) : on) set.add(c); else set.delete(c); },
|
||||
};
|
||||
}
|
||||
|
||||
function fakeEl(id) {
|
||||
return {
|
||||
id,
|
||||
value: '',
|
||||
innerHTML: '',
|
||||
textContent: '',
|
||||
classList: fakeClassList(),
|
||||
options: [],
|
||||
appendChild(opt) { this.options.push(opt); },
|
||||
};
|
||||
}
|
||||
|
||||
function fakeRamDocument(ids) {
|
||||
const els = {};
|
||||
for (const id of ids) els[id] = fakeEl(id);
|
||||
const sel = els['ram-card-sel'];
|
||||
if (sel) {
|
||||
Object.defineProperty(sel, 'innerHTML', {
|
||||
get() { return this._html || ''; },
|
||||
set(v) { this._html = v; this.value = ''; },
|
||||
});
|
||||
}
|
||||
globalThis.document = {
|
||||
getElementById: id => els[id] || null,
|
||||
createElement: () => fakeEl('option'),
|
||||
};
|
||||
return els;
|
||||
}
|
||||
|
||||
test('ramOpChanged clears the executed status only on a real op change', () => {
|
||||
const els = fakeRamDocument(['ram-op', 'ram-install-params', 'ram-result', 'ram-explorer', 'ram-steps', 'ram-progress']);
|
||||
_ramOpLast = null;
|
||||
els['ram-op'].value = 'explore';
|
||||
ramOpChanged();
|
||||
assert.ok(!els['ram-result'].classList.contains('hidden'));
|
||||
els['ram-result'].classList.remove('hidden');
|
||||
els['ram-steps'].classList.remove('hidden');
|
||||
ramOpChanged();
|
||||
assert.ok(!els['ram-result'].classList.contains('hidden'), 'same op must keep the result');
|
||||
els['ram-op'].value = 'install-cap';
|
||||
ramOpChanged();
|
||||
assert.ok(els['ram-result'].classList.contains('hidden'));
|
||||
assert.ok(els['ram-steps'].classList.contains('hidden'));
|
||||
assert.ok(els['ram-explorer'].classList.contains('hidden'));
|
||||
assert.ok(els['ram-progress'].classList.contains('hidden'));
|
||||
assert.ok(!els['ram-install-params'].classList.contains('hidden'));
|
||||
});
|
||||
|
||||
test('ramRender keeps the selected card preset across rebuilds', () => {
|
||||
const els = fakeRamDocument(['ram-card-sel', 'ram-op', 'ram-install-params', 'ram-result', 'ram-explorer', 'ram-steps', 'ram-progress']);
|
||||
globalThis.cards = [{ name: 'A' }, { name: 'B' }, { name: 'C' }];
|
||||
_ramCardIdx = null;
|
||||
_ramOpLast = 'explore';
|
||||
els['ram-op'].value = 'explore';
|
||||
ramRender();
|
||||
assert.strictEqual(els['ram-card-sel'].value, '');
|
||||
els['ram-card-sel'].value = '1';
|
||||
ramRender();
|
||||
assert.strictEqual(els['ram-card-sel'].value, '1');
|
||||
els['ram-card-sel'].value = '';
|
||||
_ramCardIdx = 2;
|
||||
ramRender();
|
||||
assert.strictEqual(els['ram-card-sel'].value, '2');
|
||||
globalThis.cards = [{ name: 'A' }];
|
||||
_ramCardIdx = 2;
|
||||
ramRender();
|
||||
assert.strictEqual(els['ram-card-sel'].value, '');
|
||||
delete globalThis.cards;
|
||||
});
|
||||
|
||||
test('ramApplyCard remembers a valid picked preset', () => {
|
||||
globalThis.cards = [{ name: 'A' }, { name: 'B' }];
|
||||
let applied = null;
|
||||
globalThis.cardsApply = i => { applied = i; };
|
||||
_ramCardIdx = null;
|
||||
ramApplyCard('1');
|
||||
assert.strictEqual(_ramCardIdx, 1);
|
||||
assert.strictEqual(applied, '1');
|
||||
ramApplyCard('');
|
||||
assert.strictEqual(_ramCardIdx, 1, 'invalid pick must not forget the preset');
|
||||
delete globalThis.cards;
|
||||
delete globalThis.cardsApply;
|
||||
});
|
||||
|
||||
test('ramExecute commits the dropdown selection before running', async () => {
|
||||
const els = fakeRamDocument(['ram-card-sel', 'ram-op', 'ram-install-params', 'ram-result', 'ram-explorer', 'ram-steps', 'ram-progress']);
|
||||
globalThis.cards = [{ name: 'A' }];
|
||||
globalThis.getRamSpParams = () => ({ kicKey: '11', kidKey: '22' });
|
||||
let explored = false;
|
||||
globalThis.ramExplore = async () => { explored = true; };
|
||||
globalThis.alert = () => {};
|
||||
_ramCardIdx = null;
|
||||
els['ram-card-sel'].value = '0';
|
||||
els['ram-op'].value = 'explore';
|
||||
await ramExecute();
|
||||
assert.strictEqual(_ramCardIdx, 0);
|
||||
assert.ok(explored);
|
||||
delete globalThis.cards;
|
||||
delete globalThis.getRamSpParams;
|
||||
delete globalThis.ramExplore;
|
||||
delete globalThis.alert;
|
||||
});
|
||||
|
||||
test('ramCardIdxAfterRemove keeps the remembered index aligned', () => {
|
||||
assert.strictEqual(ramCardIdxAfterRemove(2, 0), 1);
|
||||
assert.strictEqual(ramCardIdxAfterRemove(0, 0), null);
|
||||
assert.strictEqual(ramCardIdxAfterRemove(0, 2), 0);
|
||||
assert.strictEqual(ramCardIdxAfterRemove(null, 1), null);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user