My Sea iter 4b polish v2: drop FYI from locked-draw Brief; dynamic aria-selected per default_spread; defensive cross data-spread sync on init (guards bf-cache drift causing all 6 slots to render post-DEL+reload) — TDD
(1) FYI removal — the locked-draw Brief is purely informational (status + next-free-draw timestamp). No navigation target made sense for the FYI; drop it after Brief.showBanner renders. The NVM dismiss + dedicated `<time>` slot carry all the affordance the user needs. (2) Dynamic aria-selected on the SPREAD combobox — previously the SAO option was hardcoded `aria-selected="true"`. When active_draw is non-SAO (e.g. Celtic Cross), server-rendered state was internally inconsistent: hidden value = waite-smith, aria-selected = SAO. JS init's force-sync (which reads aria-selected to override autofill on hidden) then overwrote the correct hidden value w. SAO — corrupting the picker's state silently. Made aria-selected + `.sea-select-current` visible label both branch on `default_spread`. (3) Defensive cross.data-spread sync on init — after the autofill force-sync settles `hidden.value` from the aria-selected source-of-truth, mirror it onto `.my-sea-cross[data-spread]` + re-run syncLabels. Idempotent when server-rendered state is internally consistent; corrective when a prior page state (Firefox bfcache restoring a Celtic-Cross DOM, mid-draw session restored) left a stale `data-spread` that SCSS-hides the wrong subset of cells. User-reported 2026-05-20: after locking a Celtic Cross + DEL + reload, all 6 slots remained visible on the picker w. SAO labels — exactly the symptom of cross.data-spread="waite-smith" surviving an otherwise-fresh server render. Tests: 116 gameboard ITs + 5 iter-4b FTs green. The dynamic aria-selected behavior is implicitly covered by the existing default-spread IT (no regression on the SAO=true baseline); the bf-cache scenario is hard to express as a deterministic FT/IT — the defensive sync is a safety net, not a behavioral spec. Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -157,17 +157,17 @@
|
|||||||
aria-haspopup="listbox"
|
aria-haspopup="listbox"
|
||||||
aria-labelledby="id_sea_spread_label"
|
aria-labelledby="id_sea_spread_label"
|
||||||
tabindex="0">
|
tabindex="0">
|
||||||
<span class="sea-select-current">Situation, Action, Outcome</span>
|
<span class="sea-select-current">{% if default_spread == 'past-present-future' %}Past, Present, Future{% elif default_spread == 'mind-body-spirit' %}Mind, Body, Spirit{% elif default_spread == 'desire-obstacle-solution' %}Desire, Obstacle, Solution{% elif default_spread == 'waite-smith' %}Celtic Cross, Waite-Smith{% elif default_spread == 'escape-velocity' %}Celtic Cross, Escape Velocity{% else %}Situation, Action, Outcome{% endif %}</span>
|
||||||
<span class="sea-select-arrow" aria-hidden="true">▾</span>
|
<span class="sea-select-arrow" aria-hidden="true">▾</span>
|
||||||
<ul class="sea-select-list" role="listbox">
|
<ul class="sea-select-list" role="listbox">
|
||||||
<li role="presentation" class="sea-select-divider">3-card spreads</li>
|
<li role="presentation" class="sea-select-divider">3-card spreads</li>
|
||||||
<li role="option" data-value="past-present-future" aria-selected="false">Past, Present, Future</li>
|
<li role="option" data-value="past-present-future" aria-selected="{% if default_spread == 'past-present-future' %}true{% else %}false{% endif %}">Past, Present, Future</li>
|
||||||
<li role="option" data-value="situation-action-outcome" aria-selected="true">Situation, Action, Outcome</li>
|
<li role="option" data-value="situation-action-outcome" aria-selected="{% if default_spread == 'situation-action-outcome' %}true{% else %}false{% endif %}">Situation, Action, Outcome</li>
|
||||||
<li role="option" data-value="mind-body-spirit" aria-selected="false">Mind, Body, Spirit</li>
|
<li role="option" data-value="mind-body-spirit" aria-selected="{% if default_spread == 'mind-body-spirit' %}true{% else %}false{% endif %}">Mind, Body, Spirit</li>
|
||||||
<li role="option" data-value="desire-obstacle-solution" aria-selected="false">Desire, Obstacle, Solution</li>
|
<li role="option" data-value="desire-obstacle-solution" aria-selected="{% if default_spread == 'desire-obstacle-solution' %}true{% else %}false{% endif %}">Desire, Obstacle, Solution</li>
|
||||||
<li role="presentation" class="sea-select-divider">6-card spreads</li>
|
<li role="presentation" class="sea-select-divider">6-card spreads</li>
|
||||||
<li role="option" data-value="waite-smith" aria-selected="false">Celtic Cross, Waite-Smith</li>
|
<li role="option" data-value="waite-smith" aria-selected="{% if default_spread == 'waite-smith' %}true{% else %}false{% endif %}">Celtic Cross, Waite-Smith</li>
|
||||||
<li role="option" data-value="escape-velocity" aria-selected="false">Celtic Cross, Escape Velocity</li>
|
<li role="option" data-value="escape-velocity" aria-selected="{% if default_spread == 'escape-velocity' %}true{% else %}false{% endif %}">Celtic Cross, Escape Velocity</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -578,6 +578,12 @@
|
|||||||
// attribute intact for accessibility tooling).
|
// attribute intact for accessibility tooling).
|
||||||
var ts = banner.querySelector('.note-banner__timestamp');
|
var ts = banner.querySelector('.note-banner__timestamp');
|
||||||
if (ts && iso) ts.textContent = _formatTimestamp(iso);
|
if (ts && iso) ts.textContent = _formatTimestamp(iso);
|
||||||
|
// No FYI on this Brief — it's an informational nudge
|
||||||
|
// (locked draw status), not a navigation target. The
|
||||||
|
// NVM button + timestamp slot carry all the affordance
|
||||||
|
// the user needs.
|
||||||
|
var fyi = banner.querySelector('.note-banner__fyi');
|
||||||
|
if (fyi) fyi.remove();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
function _postLock(hand) {
|
function _postLock(hand) {
|
||||||
@@ -646,6 +652,18 @@
|
|||||||
if (_initialOpt && hidden.value !== _initialOpt.dataset.value) {
|
if (_initialOpt && hidden.value !== _initialOpt.dataset.value) {
|
||||||
hidden.value = _initialOpt.dataset.value;
|
hidden.value = _initialOpt.dataset.value;
|
||||||
}
|
}
|
||||||
|
// Mirror the hidden value onto the cross's `data-spread` +
|
||||||
|
// re-run syncLabels. Idempotent when server-rendered state
|
||||||
|
// is internally consistent; corrective if a prior page
|
||||||
|
// state (Firefox bfcache restoring a Celtic-Cross DOM,
|
||||||
|
// session left mid-draw etc.) left a stale `data-spread`
|
||||||
|
// that SCSS-hides the wrong subset of cells. Without this,
|
||||||
|
// a post-DEL reload could land on the picker w. data-
|
||||||
|
// spread="waite-smith" but SAO labels + SAO hidden value
|
||||||
|
// → all 6 cells visible, sometimes unlabeled (the user-
|
||||||
|
// observed bug, 2026-05-20).
|
||||||
|
cross.setAttribute('data-spread', hidden.value);
|
||||||
|
syncLabels(hidden.value);
|
||||||
|
|
||||||
// Exposed for iter 4b / future surfaces.
|
// Exposed for iter 4b / future surfaces.
|
||||||
window._mySeaDrawOrder = DRAW_ORDER;
|
window._mySeaDrawOrder = DRAW_ORDER;
|
||||||
|
|||||||
Reference in New Issue
Block a user