BUG: live preview broken after #28 (gallery) — likely JS halt in media preview wiring #30

Closed
opened 2026-06-18 12:56:47 +00:00 by mAi · 2 comments
Collaborator

Bug (regression from #28, live on sendmy.cards)

m: „jetzt klappt das preview nicht mehr.“ The #15 live card preview stopped working after the #28 gallery merge.

otto-head diagnosis (head start)

#28 added the media-source toggle (media_source = upload | gallery) and a gallery grid to compose. The preview JS (compose.html ~L269+) still wires the unified upload input: around L320 it does mediaInput.addEventListener('change', …). Strong suspicion: with the new toggle, mediaInput can be null / not present in some state (e.g. when media_source=gallery, or the input got restructured), so the script throws early — and a single uncaught exception there halts the WHOLE inline script, killing not just media preview but the card preview (#previewSection/#cardPreview), the Wunsch-Adresse URL preview, and the occasion→theme live updates too. That matches 'preview doesn't work anymore'.

Fix

  1. Reproduce in a browser (the worker has playwright) — check the JS console for the error.
  2. Null-guard the media-input wiring (don't assume mediaInput exists; guard every getElementById/querySelector before addEventListener).
  3. Feed gallery picks into the live preview too (#28 said it wired gallery into preview — verify it actually does): selecting a gallery tile should update #cardPreview (image from the asset URL), same as an uploaded file. Switching the source toggle should refresh the preview.
  4. Make the whole inline script resilient — an error in one feature block shouldn't kill the others (wrap independent blocks / guard nulls).

Constraints

CSS/JS/markup only (no backend/schema change expected). Mobile-first, German. No regression to #15 (preview), #24/#25 (styling), #28 (gallery), occasion→theme, URL preview.

DoD

  • Live preview works again (card preview + media preview + URL preview + occasion→theme), in BOTH upload and gallery source modes; switching source/occasion updates it. No JS console errors. Reproduced + verified in a browser. build green; commit references this issue. otto-head merges + deploys.
## Bug (regression from #28, live on sendmy.cards) m: *„jetzt klappt das preview nicht mehr.“* The #15 live card preview stopped working after the #28 gallery merge. ## otto-head diagnosis (head start) #28 added the **media-source toggle** (`media_source` = upload | gallery) and a gallery grid to compose. The preview JS (compose.html ~L269+) still wires the unified upload input: around **L320** it does `mediaInput.addEventListener('change', …)`. Strong suspicion: with the new toggle, **`mediaInput` can be null / not present** in some state (e.g. when `media_source=gallery`, or the input got restructured), so the script **throws early** — and a single uncaught exception there halts the WHOLE inline script, killing not just media preview but the **card preview (`#previewSection`/`#cardPreview`), the Wunsch-Adresse URL preview, and the occasion→theme live updates** too. That matches 'preview doesn't work anymore'. ## Fix 1. Reproduce in a browser (the worker has playwright) — check the JS console for the error. 2. Null-guard the media-input wiring (don't assume `mediaInput` exists; guard every getElementById/querySelector before addEventListener). 3. **Feed gallery picks into the live preview too** (#28 said it wired gallery into preview — verify it actually does): selecting a gallery tile should update `#cardPreview` (image from the asset URL), same as an uploaded file. Switching the source toggle should refresh the preview. 4. Make the whole inline script resilient — an error in one feature block shouldn't kill the others (wrap independent blocks / guard nulls). ## Constraints CSS/JS/markup only (no backend/schema change expected). Mobile-first, German. No regression to #15 (preview), #24/#25 (styling), #28 (gallery), occasion→theme, URL preview. ## DoD - Live preview works again (card preview + media preview + URL preview + occasion→theme), in BOTH upload and gallery source modes; switching source/occasion updates it. No JS console errors. Reproduced + verified in a browser. build green; commit references this issue. otto-head merges + deploys.
mAi self-assigned this 2026-06-18 12:56:47 +00:00
Author
Collaborator

Fixed — root cause was a JS halt, but not where the head guessed

Reproduced in headless Chromium (playwright). The console showed the real error:

Uncaught ReferenceError: Cannot access 'radioVal' before initialization

mediaInput is not the culprit — #media is emitted unconditionally, so it's never null. The actual halt was a temporal-dead-zone error:

Bug 1 (primary halt) — radioVal used before its const declaration

The gallery init calls filterGallery() at load (compose.html), which calls radioVal('occasion'). But radioVal / el / todayStr were declared as const after the gallery block. const isn't hoisted (TDZ), so the call threw — a single uncaught error that halted the whole inline script and killed every live preview: card preview, media thumbnails, URL preview, occasion→theme. It only fires when GalleryAssets exist, i.e. exactly the live state after #28. That's why „das preview klappt nicht mehr“.

Bug 2 (co-regression) — slug .seg shadowed by the new media-source .seg

#28 added <div class="seg media-source">, which now precedes the slug <div class="seg" data-base=...> in the DOM. querySelector('.seg') therefore bound the URL-preview block to the wrong element, leaving the to/·from/ prefix radios unwired. Now selected via .seg[data-base].

Fix (CSS/JS/markup only — no backend/schema change)

  • Hoisted the shared helpers (el/radioVal/todayStr) above all feature blocks; all shared state/functions live at module scope.
  • Null-guarded the media wiring (mediaInput/preview/videoPreview).
  • Isolated each enhancement in a block() wrapper so a fault in one feature is logged to console but can't halt the others (resilient inline script, per DoD point 4).
  • Verified gallery picks do feed the live card preview, and switching source/occasion refreshes it (DoD point 3).

Verification (playwright, headless Chromium)

Faithful harness with the real inline script + gallery markup. Results:

Check Before After
Console errors ReferenceError: radioVal ×4 none
Preview section revealed no (stayed hidden) yes
Card preview on type dead populates (msg + sender + badge)
URL preview prefix switch broken (unwired) to/oma-erika, from/test
Pane switch upload↔gallery dead works
Gallery pick → card preview no image image shown + hidden gallery_asset_id written
Back to upload clears gallery img yes
occasion→theme + badge (survived) dusk + 🎄 Weihnachten
No-gallery path n/a unaffected, no errors

go build ./... green · go test ./internal/server/... green.

Both upload and gallery source modes work; switching source/occasion updates the preview; no JS console errors. Ready for otto-head to merge + deploy.

Commit: cbab605a7c
Branch: mai/hermes/issue-30-bug-live

## Fixed — root cause was a JS halt, but **not** where the head guessed Reproduced in headless Chromium (playwright). The console showed the real error: ``` Uncaught ReferenceError: Cannot access 'radioVal' before initialization ``` `mediaInput` is **not** the culprit — `#media` is emitted unconditionally, so it's never null. The actual halt was a **temporal-dead-zone** error: ### Bug 1 (primary halt) — `radioVal` used before its `const` declaration The gallery init calls `filterGallery()` at load (compose.html), which calls `radioVal('occasion')`. But `radioVal` / `el` / `todayStr` were declared as `const` **after** the gallery block. `const` isn't hoisted (TDZ), so the call threw — a single uncaught error that halted the **whole** inline script and killed every live preview: card preview, media thumbnails, URL preview, occasion→theme. It only fires when `GalleryAssets` exist, i.e. exactly the live state after #28. That's why „das preview klappt nicht mehr“. ### Bug 2 (co-regression) — slug `.seg` shadowed by the new media-source `.seg` #28 added `<div class="seg media-source">`, which now precedes the slug `<div class="seg" data-base=...>` in the DOM. `querySelector('.seg')` therefore bound the URL-preview block to the **wrong** element, leaving the `to/`·`from/` prefix radios unwired. Now selected via `.seg[data-base]`. ## Fix (CSS/JS/markup only — no backend/schema change) - Hoisted the shared helpers (`el`/`radioVal`/`todayStr`) above all feature blocks; all shared state/functions live at module scope. - Null-guarded the media wiring (`mediaInput`/`preview`/`videoPreview`). - Isolated each enhancement in a `block()` wrapper so a fault in one feature is logged to console but **can't halt the others** (resilient inline script, per DoD point 4). - Verified gallery picks **do** feed the live card preview, and switching source/occasion refreshes it (DoD point 3). ## Verification (playwright, headless Chromium) Faithful harness with the real inline script + gallery markup. Results: | Check | Before | After | |---|---|---| | Console errors | `ReferenceError: radioVal` ×4 | **none** | | Preview section revealed | no (stayed hidden) | **yes** | | Card preview on type | dead | **populates** (msg + sender + badge) | | URL preview prefix switch | broken (unwired) | `to/oma-erika`, `from/test` ✔ | | Pane switch upload↔gallery | dead | **works** | | Gallery pick → card preview | no image | **image shown** + hidden `gallery_asset_id` written | | Back to upload clears gallery img | — | **yes** | | occasion→theme + badge | (survived) | `dusk` + 🎄 Weihnachten | | No-gallery path | n/a | **unaffected**, no errors | `go build ./...` green · `go test ./internal/server/...` green. Both upload and gallery source modes work; switching source/occasion updates the preview; no JS console errors. Ready for otto-head to merge + deploy. Commit: https://mgit.msbls.de/m/postcards/commit/cbab605a7cb0d651f448601b45f452bc2ebddaa5 Branch: `mai/hermes/issue-30-bug-live`
Author
Collaborator

Merged & deployed (merge ad416c4)

Root cause: a TDZ ReferenceError (radioVal used before its const, only triggered once gallery assets exist = post-#28) halted the whole inline compose script — plus a co-regression where the new .seg media-source shadowed the slug .seg querySelector. Both fixed: helpers hoisted, null-guards, each enhancement isolated in a block() wrapper so one fault can't kill the others, slug seg selected via .seg[data-base]. Verified in headless Chromium (playwright). JS/markup only. build green. Please confirm the preview works for you again. Not closing — m closes.

## ✅ Merged & deployed (merge `ad416c4`) Root cause: a TDZ ReferenceError (`radioVal` used before its `const`, only triggered once gallery assets exist = post-#28) halted the whole inline compose script — plus a co-regression where the new `.seg media-source` shadowed the slug `.seg` querySelector. Both fixed: helpers hoisted, null-guards, each enhancement isolated in a `block()` wrapper so one fault can't kill the others, slug seg selected via `.seg[data-base]`. Verified in headless Chromium (playwright). JS/markup only. build green. Please confirm the preview works for you again. Not closing — m closes.
mAi closed this issue 2026-06-23 15:48:04 +00:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/postcards#30
No description provided.