ui: the keyset selector is disabled and cleared while no preset is selected

A keyset only exists inside a card preset, but the SCP80/RAM/TAR keyset
selectors stayed enabled with no preset selected - showing either
"— no keyset —" or a stale "Keyset N — not defined in the preset" entry left
over from an earlier preset.  spKeysetSync() now disables the selector and
reduces it to a "— select a card preset —" placeholder whenever its view has
no preset selected, and re-enables/populates it as soon as one is.

Clearing the preset dropdown ("— Select card —") also refreshed nothing:
cardsApply() returned before the sync, so the stale keyset list stayed; it now
syncs the selectors (and the preset warning) on the empty selection too.

The three selects get disabled:opacity-40 disabled:cursor-not-allowed (the
rules are already in the compiled style.css).  Tests: keysets.test.js covers
the disabled/cleared state and the re-enable plus a cardsApply source guard;
cards_form.test.js and cards_counter.test.js gain tarPresetIdx in their
sandboxes.  Help EN/RU and both AGENTS files; sw cache simple-v343.
This commit is contained in:
2026-10-01 21:41:07 +03:00
parent cafec549fa
commit 12da7ed593
7 changed files with 79 additions and 27 deletions
+30 -20
View File
@@ -529,7 +529,7 @@
<option value="" data-l10n="— Select card —">— Select card —</option>
</select>
<label class="block mt-2 mb-1 text-sm font-medium text-gray-700 dark:text-slate-300" data-l10n="Keyset">Keyset</label>
<select id="sp-keyset-sel" onchange="spKeysetChanged()" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800"></select>
<select id="sp-keyset-sel" onchange="spKeysetChanged()" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800 disabled:opacity-40 disabled:cursor-not-allowed"></select>
</div>
<div id="sp-preset-warning" class="hidden mb-3 px-3 py-2 rounded border border-amber-400 dark:border-amber-600 bg-amber-50 dark:bg-amber-900/20 text-sm text-amber-700 dark:text-amber-300"></div>
@@ -696,7 +696,7 @@
</div>
<div class="flex-1">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300" data-l10n="Keyset">Keyset</label>
<select id="ram-keyset-sel" onchange="ramKeysetChanged()" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800"></select>
<select id="ram-keyset-sel" onchange="ramKeysetChanged()" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800 disabled:opacity-40 disabled:cursor-not-allowed"></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>
@@ -923,7 +923,7 @@
</div>
<div class="flex-1">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-slate-300" data-l10n="Keyset">Keyset</label>
<select id="tar-keyset-sel" onchange="tarKeysetChanged()" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800"></select>
<select id="tar-keyset-sel" onchange="tarKeysetChanged()" class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-1.5 dark:bg-slate-800 disabled:opacity-40 disabled:cursor-not-allowed"></select>
</div>
</div>
<div id="tar-preset-warning" class="hidden mb-3 px-3 py-2 rounded border border-amber-400 dark:border-amber-600 bg-amber-50 dark:bg-amber-900/20 text-sm text-amber-700 dark:text-amber-300"></div>
@@ -11464,24 +11464,27 @@ function cardsKeysetsFromForm() {
// matches their keyset number is selected; a number the preset does not define
// shows as "not defined" (and the packet actions refuse it).
function spKeysetSync() {
const spIdx = spPresetIdx();
const spPreset = spIdx >= 0 ? cards[spIdx] : null;
const kic = (document.getElementById('sp-kic-hex') || {}).value;
const kid = (document.getElementById('sp-kid-hex') || {}).value;
const spSel = document.getElementById('sp-keyset-sel');
if (spSel) spSel.innerHTML = spKeysetOptionsHtml(spPreset, kic, kid);
const ramSel = document.getElementById('ram-keyset-sel');
if (ramSel) {
const ramIdx = ramPresetIdx();
const ramPreset = ramIdx >= 0 ? cards[ramIdx] : null;
ramSel.innerHTML = spKeysetOptionsHtml(ramPreset, kic, kid);
}
const tarSel = document.getElementById('tar-keyset-sel');
if (tarSel) {
const tarIdx = tarPresetIdx();
const tarPreset = tarIdx >= 0 ? cards[tarIdx] : null;
tarSel.innerHTML = spKeysetOptionsHtml(tarPreset, kic, kid);
}
// A keyset only exists inside a card preset: with no preset selected the
// selector is disabled and cleared, so a stale "not defined in the preset"
// entry can never linger.
const sync = (selId, idxFn) => {
const sel = document.getElementById(selId);
if (!sel) return;
const idx = idxFn();
const preset = idx >= 0 ? cards[idx] : null;
if (!preset) {
sel.disabled = true;
sel.innerHTML = '<option value="">' + esc(t('\u2014 select a card preset \u2014')) + '</option>';
return;
}
sel.disabled = false;
sel.innerHTML = spKeysetOptionsHtml(preset, kic, kid);
};
sync('sp-keyset-sel', spPresetIdx);
sync('ram-keyset-sel', ramPresetIdx);
sync('tar-keyset-sel', tarPresetIdx);
}
function spKeysetApply(ks) {
@@ -11915,7 +11918,13 @@ function cardsApplyFields(idx, keepTar) {
}
function cardsApply(idx, keepTar) {
if (!cardsApplyFields(idx, keepTar)) return;
if (!cardsApplyFields(idx, keepTar)) {
// "— Select card —": there is no keyset to choose, and the preset
// warning must not outlive the selection it described.
spKeysetSync();
spPresetWarningRender();
return;
}
_genSpBuild();
spShowSizeInfo();
}
@@ -19834,6 +19843,7 @@ const LANG_RU = {
'is not defined in the preset': 'не определён в пресете',
'not defined in the preset': 'не определён в пресете',
'— no keyset —': '— нет keyset —',
'— select a card preset —': '— выберите пресет карты —',
'counter': 'счётчик',
'Define at least one keyset (KIc/KID and their keys)': 'Определите хотя бы один keyset (KIc/KID и его ключи)',
'Each keyset needs KIc, KID and both keys': 'Каждому набору нужны KIc, KID и оба ключа',