Upstream convention — elements wired up by hyperscript carry data-hyperscript-powered='true' so callers can find them. Net: core/bootstrap 17→19.
122 lines
4.1 KiB
Plaintext
122 lines
4.1 KiB
Plaintext
;; _hyperscript integration — wire _="..." attributes to compiled SX
|
|
;;
|
|
;; Entry points:
|
|
;; (hs-handler src) — compile source to callable (fn (me) ...)
|
|
;; (hs-activate! el) — activate hyperscript on a single element
|
|
;; (hs-boot!) — scan DOM, activate all _="..." elements
|
|
;; (hs-boot-subtree! root) — activate within a subtree (for HTMX swaps)
|
|
|
|
;; ── Compile source to a handler function ────────────────────────
|
|
;; Returns a function (fn (me) ...) that can be called with a DOM element.
|
|
;; Uses eval-expr-cek to turn the SX data structure into a live closure.
|
|
|
|
(begin
|
|
(define
|
|
hs-collect-vars
|
|
(fn
|
|
(sx)
|
|
(define vars (list))
|
|
(define
|
|
reserved
|
|
(list
|
|
(quote me)
|
|
(quote it)
|
|
(quote event)
|
|
(quote you)
|
|
(quote yourself)))
|
|
(define
|
|
walk
|
|
(fn
|
|
(node)
|
|
(when
|
|
(list? node)
|
|
(when
|
|
(and
|
|
(> (len node) 1)
|
|
(= (first node) (quote set!))
|
|
(symbol? (nth node 1)))
|
|
(let
|
|
((name (nth node 1)))
|
|
(when
|
|
(and
|
|
(not (some (fn (v) (= v name)) vars))
|
|
(not (some (fn (v) (= v name)) reserved)))
|
|
(set! vars (cons name vars)))))
|
|
(for-each walk node))))
|
|
(walk sx)
|
|
vars))
|
|
(define
|
|
hs-handler
|
|
(fn
|
|
(src)
|
|
(let
|
|
((sx (hs-to-sx-from-source src)))
|
|
(let
|
|
((extra-vars (hs-collect-vars sx)))
|
|
(do
|
|
(for-each
|
|
(fn (v) (eval-expr-cek (list (quote define) v nil)))
|
|
extra-vars)
|
|
(let
|
|
((guarded (list (quote guard) (list (quote _e) (list (quote true) (list (quote if) (list (quote and) (list (quote list?) (quote _e)) (list (quote =) (list (quote first) (quote _e)) "hs-return")) (list (quote nth) (quote _e) 1) (list (quote raise) (quote _e))))) sx)))
|
|
(eval-expr-cek
|
|
(list
|
|
(quote fn)
|
|
(list (quote me))
|
|
(list
|
|
(quote let)
|
|
(list (list (quote it) nil) (list (quote event) nil))
|
|
guarded))))))))))
|
|
|
|
;; ── Activate a single element ───────────────────────────────────
|
|
;; Reads the _="..." attribute, compiles, and executes with me=element.
|
|
;; Marks the element to avoid double-activation.
|
|
|
|
(define
|
|
hs-activate!
|
|
(fn
|
|
(el)
|
|
(let
|
|
((src (dom-get-attr el "_")) (prev (dom-get-data el "hs-script")))
|
|
(when
|
|
(and src (not (= src prev)))
|
|
(dom-set-data el "hs-script" src)
|
|
(dom-set-data el "hs-active" true)
|
|
(dom-set-attr el "data-hyperscript-powered" "true")
|
|
(let ((handler (hs-handler src))) (handler el))))))
|
|
|
|
;; ── Boot: scan entire document ──────────────────────────────────
|
|
;; Called once at page load. Finds all elements with _ attribute,
|
|
;; compiles their hyperscript, and activates them.
|
|
|
|
(define
|
|
hs-deactivate!
|
|
(fn
|
|
(el)
|
|
(let
|
|
((unlisteners (or (dom-get-data el "hs-unlisteners") (list))))
|
|
(for-each (fn (u) (when u (u))) unlisteners)
|
|
(dom-set-data el "hs-unlisteners" (list))
|
|
(dom-set-data el "hs-active" false)
|
|
(dom-set-data el "hs-script" nil))))
|
|
|
|
;; ── Boot subtree: for dynamic content ───────────────────────────
|
|
;; Called after HTMX swaps or dynamic DOM insertion.
|
|
;; Only activates elements within the given root.
|
|
|
|
(define
|
|
hs-boot!
|
|
(fn
|
|
()
|
|
(let
|
|
((elements (dom-query-all (host-get (host-global "document") "body") "[_]")))
|
|
(for-each (fn (el) (hs-activate! el)) elements))))
|
|
|
|
(define
|
|
hs-boot-subtree!
|
|
(fn
|
|
(root)
|
|
(let
|
|
((elements (dom-query-all root "[_]")))
|
|
(for-each (fn (el) (hs-activate! el)) elements))
|
|
(when (dom-get-attr root "_") (hs-activate! root)))) |