host: block-editor card-type <select> options are direct children (populate on boosted nav)
The add-block dropdown wrapped its <option>s in a <span> — (select :name "ctype" (span (option…)…)) — to splice a dynamic list. A <select> only renders <option>/<optgroup> direct children, so the dropdown was empty. A full-page load hid it (the browser's HTML parser hoists mis-nested options out of the select), but on a BOOSTED nav the DOM is built programmatically (no parser error-recovery), so the span stayed and the dropdown was empty. The card types are a fixed set — inline the options directly as <select> children. TEST-FIRST: 4th boost-nav.spec.js case (LOGGED IN: boosted nav to edit → assert select[name=ctype] > option count is 5, incl card-heading). RED before (0 direct-child options — span-wrapped), GREEN after. All 4 boost-nav tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1374,16 +1374,23 @@
|
|||||||
(define host/blog--block-editor
|
(define host/blog--block-editor
|
||||||
(fn (slug)
|
(fn (slug)
|
||||||
(let ((refs (host/blog-body-refs slug)))
|
(let ((refs (host/blog-body-refs slug)))
|
||||||
(let ((rows (map (fn (c) (host/blog--block-row slug c)) refs))
|
(let ((rows (map (fn (c) (host/blog--block-row slug c)) refs)))
|
||||||
(type-opts (map (fn (ct) (quasiquote (option :value (unquote ct) (unquote ct))))
|
|
||||||
(list "card-heading" "card-text" "card-quote" "card-code" "card-callout"))))
|
|
||||||
(quasiquote
|
(quasiquote
|
||||||
(div :id "block-editor" :style "margin-top:1.5em;border-top:1px solid #ccc;padding-top:1em"
|
(div :id "block-editor" :style "margin-top:1.5em;border-top:1px solid #ccc;padding-top:1em"
|
||||||
(h3 :style "font-size:1em;margin:0 0 0.3em" "Blocks")
|
(h3 :style "font-size:1em;margin:0 0 0.3em" "Blocks")
|
||||||
(unquote (if (> (len refs) 0) (cons (quote ul) rows) (quote (p :style "color:#999" "No blocks yet."))))
|
(unquote (if (> (len refs) 0) (cons (quote ul) rows) (quote (p :style "color:#999" "No blocks yet."))))
|
||||||
(form :method "post" :action (unquote (str "/" slug "/blocks/add"))
|
(form :method "post" :action (unquote (str "/" slug "/blocks/add"))
|
||||||
:sx-post (unquote (str "/" slug "/blocks/add")) :sx-target "#block-editor" :sx-swap "outerHTML"
|
:sx-post (unquote (str "/" slug "/blocks/add")) :sx-target "#block-editor" :sx-swap "outerHTML"
|
||||||
(select :name "ctype" (unquote (cons (quote span) type-opts)))
|
;; options MUST be DIRECT children of <select> — a wrapper (e.g. a span to splice
|
||||||
|
;; a dynamic list) leaves the dropdown empty when the DOM is built programmatically
|
||||||
|
;; on a boosted swap (a full-page HTML parse would hoist them out, masking it). The
|
||||||
|
;; card types are a fixed set, so inline them.
|
||||||
|
(select :name "ctype"
|
||||||
|
(option :value "card-heading" "heading")
|
||||||
|
(option :value "card-text" "text")
|
||||||
|
(option :value "card-quote" "quote")
|
||||||
|
(option :value "card-code" "code")
|
||||||
|
(option :value "card-callout" "callout"))
|
||||||
" " (input :name "text" :placeholder "text…" :style "width:50%")
|
" " (input :name "text" :placeholder "text…" :style "width:50%")
|
||||||
" " (button :type "submit" "+ add block"))))))))
|
" " (button :type "submit" "+ add block"))))))))
|
||||||
|
|
||||||
|
|||||||
@@ -88,4 +88,20 @@ test.describe('boosted navigation (browser-only)', () => {
|
|||||||
await expect(page.locator('body')).toContainText('Posts', { timeout: 12000 });
|
await expect(page.locator('body')).toContainText('Posts', { timeout: 12000 });
|
||||||
expect(new URL(page.url()).pathname).toBe('/');
|
expect(new URL(page.url()).pathname).toBe('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('LOGGED IN: the block-editor card-type dropdown populates after a boosted nav to edit', async ({ page }) => {
|
||||||
|
test.setTimeout(90000);
|
||||||
|
await login(page);
|
||||||
|
await page.goto(BASE + '/');
|
||||||
|
await waitReady(page);
|
||||||
|
await page.locator('a[href="/compose-demo/"]').first().click();
|
||||||
|
await expect(page.locator('body')).toContainText('composition object', { timeout: 15000 });
|
||||||
|
await page.locator('a[href="/compose-demo/edit"]').last().click();
|
||||||
|
await expect(page.locator('body')).toContainText('Edit:', { timeout: 15000 });
|
||||||
|
// the ctype <select> must have selectable <option> DIRECT children. A <span> wrapper
|
||||||
|
// leaves the dropdown empty when the DOM is built programmatically on a boosted swap
|
||||||
|
// (the HTML parser would hoist them out on a full load, hiding the bug there).
|
||||||
|
await expect(page.locator('#block-editor select[name="ctype"] > option')).toHaveCount(5, { timeout: 10000 });
|
||||||
|
await expect(page.locator('#block-editor select[name="ctype"] > option[value="card-heading"]')).toHaveCount(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user