host: block editor — edit the :body composition (composition roadmap step 6)
The post body is now editable as a composition. Model ops over the :body ref-seq (and the
ordered `contains` edges): host/blog-block-add! (create a card object is-a a card-type +
fields, contains edge, append a ref), -remove! (drop ref + edge), -move! (swap adjacent).
host/blog--block-editor renders a row per block — type + a content preview + ↑/↓/remove
controls + a "fields" link — plus an add-block form, injected into the edit page. Routes
POST /:slug/blocks/{add, :cslug/remove, :cslug/move} (guarded; SX-htmx sx-post + outerHTML
swap of #block-editor, redirect fallback for no-JS).
Cards-as-objects pays off: per-block FIELD editing is free — a card IS an object, so its
fields are edited via its own /<cslug>/edit page; the block editor only owns structure.
Guard fix: a card type is a SUBTYPE-OF card (not is-a), so the add validates ctype against
the down-closure of "card", not host/blog-is-a?. Verified via the warm server (162/164; the
2 fails are the pre-existing relate-picker pair). Deferred: Playwright live-swap check;
alt/each block insertion (the core editor handles the seq of refs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -817,6 +817,39 @@
|
||||
(let ((html (dream-resp-body (host-bl-app (host-bl-req "/imp-x/")))))
|
||||
(list (contains? html "Heading One") (contains? html "Para text.") (contains? html "p.jpg")))
|
||||
(list true true true))
|
||||
;; -- block editor: structural edits to the post :body composition (step 6). --
|
||||
(host-bl-test "block-add! creates a card object + contains edge + appends a ref to the body"
|
||||
(begin
|
||||
(host/blog-put! "bdoc" "BDoc" "(article)" "published")
|
||||
(host/blog--set-body! "bdoc" (quote (seq)))
|
||||
(let ((c0 (host/blog-block-add! "bdoc" "card-text" {"text" "first"}))
|
||||
(c1 (host/blog-block-add! "bdoc" "card-heading" {"level" "2" "text" "a head"})))
|
||||
(list (host/blog-body-refs "bdoc")
|
||||
(host/blog-is-a? c0 "card-text")
|
||||
(contains? (host/blog-out "bdoc" "contains") c1))))
|
||||
(list (list "bdoc__b0" "bdoc__b1") true true))
|
||||
(host-bl-test "block-move! reorders the body refs (and is a no-op at the ends)"
|
||||
(begin
|
||||
(host/blog-block-move! "bdoc" "bdoc__b1" "up") ;; b1 before b0
|
||||
(let ((after-up (host/blog-body-refs "bdoc")))
|
||||
(host/blog-block-move! "bdoc" "bdoc__b1" "up") ;; b1 already first -> no-op
|
||||
(list after-up (host/blog-body-refs "bdoc"))))
|
||||
(list (list "bdoc__b1" "bdoc__b0") (list "bdoc__b1" "bdoc__b0")))
|
||||
(host-bl-test "block-remove! drops the ref from the body + the contains edge"
|
||||
(begin
|
||||
(host/blog-block-remove! "bdoc" "bdoc__b1")
|
||||
(list (host/blog-body-refs "bdoc") (contains? (host/blog-out "bdoc" "contains") "bdoc__b1")))
|
||||
(list (list "bdoc__b0") false))
|
||||
(host-bl-test "the edit page shows the block editor (#block-editor + an add-block form)"
|
||||
(let ((html (dream-resp-body (host-bl-wapp (host-bl-send "GET" "/bdoc/edit" "Bearer good" "" "")))))
|
||||
(list (contains? html "block-editor") (contains? html "+ add block")))
|
||||
(list true true))
|
||||
(host-bl-test "POST /bdoc/blocks/add (auth) adds a block -> body grows"
|
||||
(begin
|
||||
(host-bl-wapp (host-bl-send "POST" "/bdoc/blocks/add" "Bearer good"
|
||||
"application/x-www-form-urlencoded" "ctype=card-text&text=added+block"))
|
||||
(len (host/blog-body-refs "bdoc")))
|
||||
2)
|
||||
(host-bl-test "a post with no schema'd type is vacuously valid"
|
||||
(host/blog-type-valid? "ppost" "(p \"anything\")") true)
|
||||
(host-bl-test "edit-submit rejects content violating the type schema (not saved)"
|
||||
|
||||
Reference in New Issue
Block a user