fix: all tabs inside the page container + compact RAM row (v3.6.46)
The max-w-7xl mx-auto page container closed before #tab-scp81, so SCP81 and Cards rendered directly under <body> and stretched to the whole window while the other five tabs were capped at 1280 px. The closing </div> moved after #tab-cards (before the modals); a structural test walks the markup and asserts every tab-content has the container as an ancestor (verified to fail on the old nesting with 'tab-scp81 must be inside the max-w-7xl page container'). The SCP80/RAM form's Card preset and Operation selects now share one flex gap-2 items-end row with Execute (guarded by a markup test). sw cache simple-v319; tests: 531 Python / 683 Node.
This commit is contained in:
+8
-9
@@ -683,14 +683,13 @@
|
||||
<div id="scp80-sub-ram" class="hidden">
|
||||
<p class="text-xs text-gray-500 dark:text-slate-400 mb-3" data-l10n="RAM operations perform atomic GlobalPlatform commands over SCP80. Card keys are taken from the saved preset.">RAM operations perform atomic GlobalPlatform commands over SCP80. Card keys are taken from the saved preset.</p>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300" data-l10n="Card preset">Card preset</label>
|
||||
<select id="ram-card-sel" onchange="ramApplyCard(this.value)" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800">
|
||||
<option value="" data-l10n="— Select card —">— Select card —</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 flex gap-2 items-end">
|
||||
<div class="flex-1">
|
||||
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300" data-l10n="Card preset">Card preset</label>
|
||||
<select id="ram-card-sel" onchange="ramApplyCard(this.value)" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800">
|
||||
<option value="" data-l10n="— Select card —">— Select card —</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300" data-l10n="Operation">Operation</label>
|
||||
<select id="ram-op" onchange="ramOpChanged()" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800">
|
||||
@@ -1354,7 +1353,6 @@
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-scp81" class="tab-content hidden">
|
||||
<div class="flex flex-wrap justify-center gap-2 mb-3">
|
||||
@@ -1603,6 +1601,7 @@
|
||||
</div>
|
||||
<div id="cards-io" class="hidden mt-2 text-xs text-gray-500 dark:text-slate-400"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="event-send-modal" class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center hidden">
|
||||
<div class="bg-white dark:bg-slate-800 rounded-lg p-6 max-w-sm w-full mx-4 max-h-[85vh] overflow-auto">
|
||||
@@ -1747,7 +1746,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.6.45';
|
||||
const SIMPLE_VERSION = '3.6.46';
|
||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||
|
||||
// ===== Tab switching =====
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
const CACHE = 'simple-v318';
|
||||
const CACHE = 'simple-v319';
|
||||
const URLS = [
|
||||
'index.html',
|
||||
'help.html',
|
||||
|
||||
@@ -448,3 +448,41 @@ test('every data-l10n attribute resolves in LANG_RU after HTML decoding', () =>
|
||||
const missing = [...new Set([...attrs, ...titles].filter(k => !(k in dict)))];
|
||||
assert.deepStrictEqual(missing, [], 'data-l10n keys with no LANG_RU entry:\n' + missing.join('\n'));
|
||||
});
|
||||
|
||||
test('every tab-content lives inside the max-w-7xl page container', () => {
|
||||
// SCP81 and Cards used to sit outside the container (its closing </div>
|
||||
// came before them), so they stretched to the whole window while the
|
||||
// other tabs were capped - v3.6.46.
|
||||
const markup = htmlOnly(html);
|
||||
const re = /<(\/?)([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*?)>/g;
|
||||
let m;
|
||||
let depth = 0;
|
||||
let containerDepth = null;
|
||||
const seen = new Set();
|
||||
while ((m = re.exec(markup))) {
|
||||
const closing = m[1] === '/';
|
||||
const tag = m[2].toLowerCase();
|
||||
const attrs = m[3] || '';
|
||||
const selfClosing = attrs.trim().endsWith('/');
|
||||
if (VOID_TAGS.has(tag) || selfClosing) continue;
|
||||
if (closing) {
|
||||
if (containerDepth !== null && depth === containerDepth) containerDepth = null;
|
||||
depth--;
|
||||
continue;
|
||||
}
|
||||
if (tag === 'div' && /class="[^"]*max-w-7xl/.test(attrs)) containerDepth = depth + 1;
|
||||
if (tag === 'div' && /class="[^"]*tab-content/.test(attrs)) {
|
||||
const id = (/id="([^"]+)"/.exec(attrs) || [])[1];
|
||||
assert.notStrictEqual(containerDepth, null,
|
||||
id + ' must be inside the max-w-7xl page container');
|
||||
seen.add(id);
|
||||
}
|
||||
depth++;
|
||||
}
|
||||
assert.strictEqual(seen.size, 7, 'expected all seven tabs, saw ' + seen.size);
|
||||
});
|
||||
|
||||
test('the RAM form shows Card preset and Operation in one row', () => {
|
||||
const row = /<div class="mb-3 flex gap-2 items-end">\s*<div class="flex-1">\s*<label[^>]*data-l10n="Card preset"[\s\S]*?id="ram-card-sel"[\s\S]*?data-l10n="Operation"[\s\S]*?id="ram-op"[\s\S]*?data-l10n="Execute"/.exec(html);
|
||||
assert.ok(row, 'Card preset + Operation + Execute must share one row');
|
||||
});
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "pysim-simple-server"
|
||||
version = "3.6.45"
|
||||
version = "3.6.46"
|
||||
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
||||
requires-python = ">=3.8"
|
||||
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
|
||||
|
||||
@@ -31,7 +31,7 @@ from osmocom.tlv import BER_TLV_IE
|
||||
from osmocom.utils import rpad
|
||||
|
||||
|
||||
VERSION = '3.6.45'
|
||||
VERSION = '3.6.46'
|
||||
|
||||
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user