diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-24 13:16:57 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-24 13:16:57 +0200 |
| commit | 4c23ae5107690a77a4253eaecbb7dfa822bdffc3 (patch) | |
| tree | 2935b0a534df0e189c49c9fad533bb79d096a636 | |
| parent | a675a983424f1f8d103fc12d55ef4f7129a92d62 (diff) | |
| download | lectio-4c23ae5107690a77a4253eaecbb7dfa822bdffc3.tar.gz lectio-4c23ae5107690a77a4253eaecbb7dfa822bdffc3.zip | |
web reader: fix chapter arrows (drive chap select) + mono (move #pane out of controls form)
| -rw-r--r-- | internal/web/server_test.go | 34 | ||||
| -rw-r--r-- | internal/web/templates/reader.html | 16 |
2 files changed, 44 insertions, 6 deletions
diff --git a/internal/web/server_test.go b/internal/web/server_test.go index 77dfe74..638eb2b 100644 --- a/internal/web/server_test.go +++ b/internal/web/server_test.go @@ -406,3 +406,37 @@ func TestChooseListener(t *testing.T) { } }) } + +// TestReaderPaneOutsideForm guards the mono fix: #pane must render AFTER the +// controls </form> so its reading text inherits body's --font-reading (which +// the mono toggle flips) instead of the form's --font-ui. +func TestReaderPaneOutsideForm(t *testing.T) { + srv := NewServer(config.Default()) + rec := httptest.NewRecorder() + srv.ServeHTTP(rec, httptest.NewRequest("GET", "/reader", nil)) + b := rec.Body.String() + f := strings.Index(b, "</form>") + p := strings.Index(b, `id="pane"`) + if f < 0 || p < 0 || p < f { + t.Errorf("#pane must render after </form> (form@%d pane@%d)", f, p) + } +} + +// TestReaderArrowsDriveChapSelect guards the chapter-nav fix: the arrows drive +// the chap <select> (single source of truth) rather than a competing hx-vals +// "chap" param, and the server renders the requested book+chapter. +func TestReaderArrowsDriveChapSelect(t *testing.T) { + srv := NewServer(config.Default()) + rec := httptest.NewRecorder() + srv.ServeHTTP(rec, httptest.NewRequest("GET", "/reader?book=Luke&chap=12", nil)) + b := rec.Body.String() + if !strings.Contains(b, "select[name=chap]") { + t.Errorf("chapter arrows should drive the chap <select>") + } + if strings.Contains(b, `hx-vals='{"chap"`) { + t.Errorf("chapter arrows must not use a competing hx-vals chap param") + } + if !strings.Contains(b, "Luke 12") { + t.Errorf("server did not render the requested Luke 12") + } +} diff --git a/internal/web/templates/reader.html b/internal/web/templates/reader.html index c82d08e..921016a 100644 --- a/internal/web/templates/reader.html +++ b/internal/web/templates/reader.html @@ -27,16 +27,17 @@ </select> </label> + {{/* Arrows drive the chapter <select> (the single source of truth) and + fire its change, so navigation always carries the CURRENT book + + target chapter -- no duplicate "chap" param from a competing hx-vals. */}} <span class="chap-nav"> - <button type="button" hx-get="/reader" hx-target="#reader-root" hx-select="#reader-root" - hx-swap="outerHTML" hx-vals='{"chap":"{{.PrevChap}}"}'>←</button> + <button type="button" onclick="var s=this.closest('.controls').querySelector('select[name=chap]');s.value='{{.PrevChap}}';s.dispatchEvent(new Event('change',{bubbles:true}));">←</button> <label>{{.L.WebChapter}} <select name="chap"> {{range .ChapOpts}}<option value="{{.N}}" {{if .Selected}}selected{{end}}>{{.N}}</option>{{end}} </select> </label> - <button type="button" hx-get="/reader" hx-target="#reader-root" hx-select="#reader-root" - hx-swap="outerHTML" hx-vals='{"chap":"{{.NextChap}}"}'>→</button> + <button type="button" onclick="var s=this.closest('.controls').querySelector('select[name=chap]');s.value='{{.NextChap}}';s.dispatchEvent(new Event('change',{bubbles:true}));">→</button> </span> {{range .VersionOpts}} @@ -50,9 +51,12 @@ <option value="interlinear" {{if eq .Display "interlinear"}}selected{{end}}>{{.L.OptInterlinear}}</option> </select> </label> - - <div id="pane">{{.Reading}}</div> </form> + + {{/* #pane is OUTSIDE the form so its reading text inherits body's + --font-reading (mono-responsive), not the form's --font-ui. It stays + inside #reader-root so an hx-select swap re-renders it with the controls. */}} + <div id="pane">{{.Reading}}</div> </div> <label class="theme-picker">{{.L.Theme}} |
