ui: embedded labels (fieldset/legend) for the phone simulator and SCP81 containers

- Phone simulator: STK menu, STATUS and Polling, TERMINAL PROFILE and
  SET UP EVENT LIST become fieldsets with legends; 'Fetched proactive
  commands:' gains a bordered container
- SCP81 listener: the HTTP OTA listener label moves into the legend (the
  live state span stays next to it), Script results (R-APDUs) and HTTP OTA
  log become fieldsets (the log's Clear button moves to the body top-right)
- Options (applied at Start) stays a details/summary but its summary is
  styled as an embedded label (page-background patch over the top border,
  native triangle kept) so it expands/collapses from the legend
- html.test.js: card-fieldset test no longer assumes exactly two fieldsets;
  new guard test for the legends and the Options summary
- Tailwind rebuild of style.css; SW cache simple-v192 (version stays 2.4.0)
This commit is contained in:
2026-09-19 21:51:03 +03:00
parent eb83238ae7
commit 158f1c676f
4 changed files with 307 additions and 55 deletions
+26 -8
View File
@@ -27,19 +27,37 @@ test('cards list shows the SCP81 PSK column with blue/red row buttons', () => {
test('the card form groups the SCP80 and SCP81 fields into labelled fieldsets', () => {
const fieldsets = [...html.matchAll(/<fieldset[\s\S]*?<\/fieldset>/g)].map(m => m[0]);
assert.strictEqual(fieldsets.length, 2);
assert.match(fieldsets[0], /<legend[^>]*data-l10n="SCP80 \(GSM 03\.48, ETSI TS 102 225\)"/);
assert.match(fieldsets[0], /id="cards-kic"/);
assert.match(fieldsets[0], /id="cards-kid-key"/);
assert.match(fieldsets[1], /<legend[^>]*data-l10n="SCP81 \(HTTP OTA\)"/);
assert.match(fieldsets[1], /id="cards-psk-id"/);
assert.match(fieldsets[1], /id="cards-psk-key"/);
const scp80 = fieldsets.find(f => /data-l10n="SCP80 \(GSM 03\.48, ETSI TS 102 225\)"/.test(f));
const scp81 = fieldsets.find(f => /data-l10n="SCP81 \(HTTP OTA\)"/.test(f));
assert.ok(scp80, 'SCP80 card fieldset not found');
assert.ok(scp81, 'SCP81 card fieldset not found');
assert.match(scp80, /id="cards-kic"/);
assert.match(scp80, /id="cards-kid-key"/);
assert.match(scp81, /id="cards-psk-id"/);
assert.match(scp81, /id="cards-psk-key"/);
// the PSK explanation lives inside the SCP81 group, not outside it
assert.match(fieldsets[1], /data-l10n="SCP81 HTTP OTA: the listener picks the key/);
assert.match(scp81, /data-l10n="SCP81 HTTP OTA: the listener picks the key/);
// the ICCID field is not in either group
assert.ok(!fieldsets.some(f => f.includes('id="cards-iccid"')));
});
test('labelled containers use fieldsets with embedded legends', () => {
const legendCls = '<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400"';
for (const label of ['STK menu', 'STATUS and Polling', 'TERMINAL PROFILE',
'Events that the card monitors (SET UP EVENT LIST):', 'Fetched proactive commands:',
'HTTP OTA log']) {
assert.ok(html.includes(legendCls + ' data-l10n="' + label + '"'), 'no legend for ' + label);
}
// legends with dynamic state spans put data-l10n on the inner span so
// translatePage() does not wipe the sibling
assert.ok(html.includes('<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400"><span data-l10n="HTTP OTA listener">HTTP OTA listener</span> <span id="scp81-state"'));
assert.ok(html.includes('<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400"><span data-l10n="Script results (R-APDUs)">Script results (R-APDUs)</span> <span id="scp81-results-state"'));
// the Options block stays a details/summary, with the summary styled as
// the embedded label (page-background patch over the border)
assert.match(html, /<details id="scp81-opts" class="border border-gray-200 dark:border-slate-700 rounded mb-3">\s*<summary class="w-fit list-inside[^"]*bg-neutral-50 dark:bg-slate-900"/);
assert.match(html, /<summary class="w-fit list-inside[^"]*">\s*<span data-l10n="Options \(applied at Start\)">/);
});
test('PLI qualifier tables cover all standard qualifiers', () => {
// ESN (07), MEID (0B) and Supported RATs (1A) must at least be named, in
// both the TR Config dictionary and the proactive-log short labels.