The .cap is only used to generate the APDUs: the script stores the APDU list, not the file.
@@ -1616,7 +1622,7 @@
// ===== Version =====
// Single source of truth for the PWA version: shown in the header and used
// by the server version check in pysimConnect().
-const SIMPLE_VERSION = '3.5.18';
+const SIMPLE_VERSION = '3.5.19';
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
// ===== Tab switching =====
@@ -8047,7 +8053,7 @@ function capMemHtml(mem) {
const part = content => cell(content, 'pl-4 text-gray-400 dark:text-slate-500');
const section = content => '
' + esc(content) + '
';
const disclosure = content => '' + esc(content) + '';
- let html = '
' + esc(t('CAP requirements (estimate)')) + '
';
+ let html = '';
// ── package identity: AIDs, header flags (Table 6-4), applets and the
// compiled-against hint (javacard.framework version + CAP format) ──
@@ -8153,22 +8159,23 @@ function capMemHtml(mem) {
function capRenderAnalysis(kind) {
const box = document.getElementById(kind === 'ram' ? 'ram-cap-info' : 'scripts-cap-info');
- if (!box) return;
+ const body = document.getElementById(kind === 'ram' ? 'ram-cap-body' : 'scripts-cap-body');
+ if (!box || !body) return;
const st = _capAnalysis[kind];
if (!st || st.status === 'idle') {
box.classList.add('hidden');
- box.innerHTML = '';
+ body.innerHTML = '';
return;
}
box.classList.remove('hidden');
if (st.status === 'analyzing') {
- box.innerHTML = '' + esc(t('Analyzing CAP file...')) + '';
+ body.innerHTML = '' + esc(t('Analyzing CAP file...')) + '';
} else if (st.status === 'error') {
- box.innerHTML = '' + esc(t('Analysis failed:')) + ' ' + esc(st.error || '') + '' +
+ body.innerHTML = '' + esc(t('Analysis failed:')) + ' ' + esc(st.error || '') + '' +
' ';
} else {
- box.innerHTML = capMemHtml(st.memory);
+ body.innerHTML = capMemHtml(st.memory);
}
}
@@ -16143,6 +16150,7 @@ const LANG_RU = {
'Analysis failed:': 'Ошибка анализа:',
'Retry': 'Повторить',
'Analyze the CAP file first': 'Сначала проанализируйте CAP-файл',
+ 'CAP details': 'Детали CAP',
'CAP requirements (estimate)': 'Требования CAP (оценка)',
'NVRAM requirement ≈': 'Требование NVRAM ≈',
'Requires:': 'Требуются:',
@@ -16929,6 +16937,9 @@ function refreshDynamicI18n() {
if (isViewVisible('tab-cards')) { cardsRender(); cardsSetFormMode(); }
if (isViewVisible('scp81-sub-scripts')) { scriptsRender(); scriptsRebuildSelect(); }
if (_ramExplorerData && isViewVisible('ram-explorer')) ramRenderExplorer();
+ // the CAP analysis bodies are built with t(); the legends are static
+ capRenderAnalysis('ram');
+ capRenderAnalysis('scripts');
if (isViewVisible('tab-phone')) {
if (isViewVisible('phone-sub-phone')) {
pysimEventsRender();
diff --git a/frontend/sw.js b/frontend/sw.js
index 883ed0d..7ff5ec2 100644
--- a/frontend/sw.js
+++ b/frontend/sw.js
@@ -1,4 +1,4 @@
-const CACHE = 'simple-v271';
+const CACHE = 'simple-v272';
const URLS = [
'index.html',
'help.html',
diff --git a/frontend/tests/capmem.test.js b/frontend/tests/capmem.test.js
index 684d5d7..9178720 100644
--- a/frontend/tests/capmem.test.js
+++ b/frontend/tests/capmem.test.js
@@ -83,7 +83,8 @@ test('capMemHtml renders the grouped report: package, requires, memory, componen
const mem = memFixture();
mem.warnings = ['method class[0].token[1]: unknown opcode 0xAA, scan stopped'];
const out = capMemHtml(mem);
- assert.ok(out.includes('CAP requirements (estimate)'), out);
+ // the border legend titles the box now; the body starts with the sections
+ assert.ok(!out.includes('CAP requirements (estimate)'), out);
// grouped, labelled sections (always visible except components/notes)
assert.ok(out.includes('>Package
'), out);
assert.ok(out.includes('>Requires (1)'), out);
@@ -228,4 +229,39 @@ test('the CAP inputs and their action buttons are wired', () => {
assert.match(html, /id="ram-cap-info"/);
assert.match(html, /id="scripts-cap-info"/);
assert.match(html, /\/api\/cap-info/);
+ // the report lives in a bordered fieldset with the title in the border
+ // (the simulator/eSIM pattern); the JS fills the body div
+ assert.match(html, /