v3.11.0 editor polish: keyset editor as a header table, in sync with TAR
The keyset rows were a stack of flex divs with no column labels. They are now a fixed-layout table like the TAR table: a thead with # (keyset number, with its tooltip), KIc, KID, KIc key, KID key, Counter and the action column, and <tr> rows of py-1 px-2 cells with w-full inputs (the columns drive the widths: 40/56/56 px, the two key columns split the remainder, 112 px for the 10-digit counter). Ids and behaviour are unchanged (the number span still toggles its red flag, the inputs keep their handlers). Guards: html.test.js checks the keyset table headers and tbody; cards_form.test.js checks the row markup. sw cache simple-v366. Tests: 665 Python + 788 frontend green; the whole inline PWA script syntax-checked.
This commit is contained in:
+22
-11
@@ -1683,7 +1683,18 @@
|
|||||||
<fieldset class="border border-gray-200 dark:border-slate-700 rounded p-3 mb-3">
|
<fieldset class="border border-gray-200 dark:border-slate-700 rounded p-3 mb-3">
|
||||||
<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="SCP80 (GSM 03.48, ETSI TS 102 225)">SCP80 (GSM 03.48, ETSI TS 102 225)</legend>
|
<legend class="px-1 text-xs font-medium text-gray-500 dark:text-slate-400" data-l10n="SCP80 (GSM 03.48, ETSI TS 102 225)">SCP80 (GSM 03.48, ETSI TS 102 225)</legend>
|
||||||
<span class="block mb-1 text-xs text-gray-600 dark:text-slate-400" data-l10n="OTA keysets — each with its own number and counter">OTA keysets — each with its own number and counter</span>
|
<span class="block mb-1 text-xs text-gray-600 dark:text-slate-400" data-l10n="OTA keysets — each with its own number and counter">OTA keysets — each with its own number and counter</span>
|
||||||
<div id="cards-keysets"></div>
|
<table class="w-full table-fixed text-sm mb-2">
|
||||||
|
<thead><tr>
|
||||||
|
<th class="w-10 text-left py-1 px-2 border-b border-gray-200 dark:border-slate-700" data-l10n-title="Keyset number (b8..b5 of KIc/KID)">#</th>
|
||||||
|
<th class="w-14 text-left py-1 px-2 border-b border-gray-200 dark:border-slate-700">KIc</th>
|
||||||
|
<th class="w-14 text-left py-1 px-2 border-b border-gray-200 dark:border-slate-700">KID</th>
|
||||||
|
<th class="text-left py-1 px-2 border-b border-gray-200 dark:border-slate-700">KIc key</th>
|
||||||
|
<th class="text-left py-1 px-2 border-b border-gray-200 dark:border-slate-700">KID key</th>
|
||||||
|
<th class="w-28 text-left py-1 px-2 border-b border-gray-200 dark:border-slate-700" data-l10n="Counter">Counter</th>
|
||||||
|
<th class="w-12 border-b border-gray-200 dark:border-slate-700"></th>
|
||||||
|
</tr></thead>
|
||||||
|
<tbody id="cards-keysets"></tbody>
|
||||||
|
</table>
|
||||||
<button type="button" onclick="cardsKeysetAdd()" class="mt-2 px-3 py-1.5 text-sm rounded bg-emerald-600 text-white hover:bg-emerald-700" data-l10n="Add keyset">Add keyset</button>
|
<button type="button" onclick="cardsKeysetAdd()" class="mt-2 px-3 py-1.5 text-sm rounded bg-emerald-600 text-white hover:bg-emerald-700" data-l10n="Add keyset">Add keyset</button>
|
||||||
<p class="text-xs text-gray-500 dark:text-slate-400 mt-2" data-l10n="KIc and KID must carry the same keyset number (their high nibble) in the range 01-0F — TS 102 225 A.2; each keyset has its own counter on the card (Annex A.1).">KIc and KID must carry the same keyset number (their high nibble) in the range 01-0F — TS 102 225 A.2; each keyset has its own counter on the card (Annex A.1).</p>
|
<p class="text-xs text-gray-500 dark:text-slate-400 mt-2" data-l10n="KIc and KID must carry the same keyset number (their high nibble) in the range 01-0F — TS 102 225 A.2; each keyset has its own counter on the card (Annex A.1).">KIc and KID must carry the same keyset number (their high nibble) in the range 01-0F — TS 102 225 A.2; each keyset has its own counter on the card (Annex A.1).</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -11815,17 +11826,17 @@ function spKeysetOptionsHtml(preset, kicHex, kidHex) {
|
|||||||
let _cardsKeysetCount = 0;
|
let _cardsKeysetCount = 0;
|
||||||
|
|
||||||
function cardsKeysetRowHtml(ks, i) {
|
function cardsKeysetRowHtml(ks, i) {
|
||||||
const cls = 'border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800 font-mono';
|
const cls = 'w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800 font-mono';
|
||||||
const kvn = spKeysetKvnOf(ks.kic);
|
const kvn = spKeysetKvnOf(ks.kic);
|
||||||
return '<div class="flex gap-2 items-center mb-1">' +
|
return '<tr>' +
|
||||||
'<span id="cards-ks-' + i + '-kvn" class="w-10 text-xs font-mono text-center text-gray-500 dark:text-slate-400" title="' + esc(t('Keyset number (b8..b5 of KIc/KID)')) + '">' + (kvn === null ? '?' : kvn) + '</span>' +
|
'<td class="py-1 px-2"><span id="cards-ks-' + i + '-kvn" class="block text-xs font-mono text-center text-gray-500 dark:text-slate-400" title="' + esc(t('Keyset number (b8..b5 of KIc/KID)')) + '">' + (kvn === null ? '?' : kvn) + '</span></td>' +
|
||||||
'<input id="cards-ks-' + i + '-kic" class="w-12 ' + cls + ' text-center" maxlength="2" placeholder="KIc" value="' + esc(ks.kic || '') + '" oninput="cardsKeysetKvnUpdate(' + i + ')">' +
|
'<td class="py-1 px-2"><input id="cards-ks-' + i + '-kic" class="' + cls + ' text-center" maxlength="2" placeholder="KIc" value="' + esc(ks.kic || '') + '" oninput="cardsKeysetKvnUpdate(' + i + ')"></td>' +
|
||||||
'<input id="cards-ks-' + i + '-kid" class="w-12 ' + cls + ' text-center" maxlength="2" placeholder="KID" value="' + esc(ks.kid || '') + '" oninput="cardsKeysetKvnUpdate(' + i + ')">' +
|
'<td class="py-1 px-2"><input id="cards-ks-' + i + '-kid" class="' + cls + ' text-center" maxlength="2" placeholder="KID" value="' + esc(ks.kid || '') + '" oninput="cardsKeysetKvnUpdate(' + i + ')"></td>' +
|
||||||
'<input id="cards-ks-' + i + '-kic-key" class="flex-1 ' + cls + '" placeholder="KIc key (hex)" value="' + esc(ks.kicKey || '') + '">' +
|
'<td class="py-1 px-2"><input id="cards-ks-' + i + '-kic-key" class="' + cls + '" placeholder="KIc key (hex)" value="' + esc(ks.kicKey || '') + '"></td>' +
|
||||||
'<input id="cards-ks-' + i + '-kid-key" class="flex-1 ' + cls + '" placeholder="KID key (hex)" value="' + esc(ks.kidKey || '') + '">' +
|
'<td class="py-1 px-2"><input id="cards-ks-' + i + '-kid-key" class="' + cls + '" placeholder="KID key (hex)" value="' + esc(ks.kidKey || '') + '"></td>' +
|
||||||
'<input id="cards-ks-' + i + '-cntr" class="w-24 ' + cls + '" maxlength="10" placeholder="Counter" value="' + esc(ks.cntr || '') + '">' +
|
'<td class="py-1 px-2"><input id="cards-ks-' + i + '-cntr" class="' + cls + '" maxlength="10" placeholder="Counter" value="' + esc(ks.cntr || '') + '"></td>' +
|
||||||
'<button type="button" onclick="cardsKeysetRemove(' + i + ')" class="px-2 py-1 text-xs rounded bg-red-600 text-white hover:bg-red-700" title="' + esc(t('Remove keyset')) + '">\u2715</button>' +
|
'<td class="py-1 px-2"><button type="button" onclick="cardsKeysetRemove(' + i + ')" class="px-2 py-1 text-xs rounded bg-red-600 text-white hover:bg-red-700" title="' + esc(t('Remove keyset')) + '">\u2715</button></td>' +
|
||||||
'</div>';
|
'</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function cardsKeysetRowsRender(keysets) {
|
function cardsKeysetRowsRender(keysets) {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simple-v365';
|
const CACHE = 'simple-v366';
|
||||||
const URLS = [
|
const URLS = [
|
||||||
'index.html',
|
'index.html',
|
||||||
'help.html',
|
'help.html',
|
||||||
|
|||||||
@@ -539,6 +539,16 @@ test('the TAR row values are left-aligned like the headers', () => {
|
|||||||
assert.match(out, /<td class="py-1 px-2"><input id="cards-tr-3-msl" class="w-full/);
|
assert.match(out, /<td class="py-1 px-2"><input id="cards-tr-3-msl" class="w-full/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the keyset row renders as a table row with full-width inputs', () => {
|
||||||
|
const out = cardsKeysetRowHtml({ kic: '15', kid: '15', kicKey: 'AA', kidKey: 'BB', cntr: '0000000001' }, 0);
|
||||||
|
assert.match(out, /^<tr>/);
|
||||||
|
assert.match(out, /<td class="py-1 px-2"><span id="cards-ks-0-kvn"/);
|
||||||
|
assert.match(out, /<td class="py-1 px-2"><input id="cards-ks-0-kic" class="w-full/);
|
||||||
|
assert.match(out, /<td class="py-1 px-2"><input id="cards-ks-0-kic-key" class="w-full/);
|
||||||
|
assert.match(out, /<td class="py-1 px-2"><input id="cards-ks-0-cntr" class="w-full/);
|
||||||
|
assert.match(out, /cardsKeysetRemove\(0\)/);
|
||||||
|
});
|
||||||
|
|
||||||
test('the TAR table renders the role rows and adds/removes free rows', () => {
|
test('the TAR table renders the role rows and adds/removes free rows', () => {
|
||||||
const els = setup();
|
const els = setup();
|
||||||
cardsTarRowsRender([{ tar: 'AF4D01', msl: '0A', desc: 'one' },
|
cardsTarRowsRender([{ tar: 'AF4D01', msl: '0A', desc: 'one' },
|
||||||
|
|||||||
@@ -152,6 +152,12 @@ test('the card editor groups its fields into labelled fieldsets', () => {
|
|||||||
// the keyset editor and the PSK pair stay as implemented
|
// the keyset editor and the PSK pair stay as implemented
|
||||||
assert.match(scp80, /id="cards-keysets"/);
|
assert.match(scp80, /id="cards-keysets"/);
|
||||||
assert.match(scp80, /onclick="cardsKeysetAdd\(\)"/);
|
assert.match(scp80, /onclick="cardsKeysetAdd\(\)"/);
|
||||||
|
// ... and mirror the TAR table: a fixed-layout table with headers
|
||||||
|
assert.match(scp80, /<table class="w-full table-fixed text-sm mb-2">/);
|
||||||
|
assert.match(scp80, /<tbody id="cards-keysets">/);
|
||||||
|
for (const h of ['KIc', 'KID', 'KIc key', 'KID key', 'Counter']) {
|
||||||
|
assert.match(scp80, new RegExp('>' + h + '</th>'));
|
||||||
|
}
|
||||||
assert.match(scp81, /id="cards-psk-id"/);
|
assert.match(scp81, /id="cards-psk-id"/);
|
||||||
assert.match(scp81, /id="cards-psk-key"/);
|
assert.match(scp81, /id="cards-psk-key"/);
|
||||||
// the PSK explanation lives inside the SCP81 group, not outside it
|
// the PSK explanation lives inside the SCP81 group, not outside it
|
||||||
|
|||||||
Reference in New Issue
Block a user