From a66b812f14dfb8c3f48b08b98e1fb9b2e6731666 Mon Sep 17 00:00:00 2001 From: Jake Date: Wed, 27 May 2026 08:00:37 -0400 Subject: [PATCH 1/2] gate ->css on "style" key --- src/borkdude/html.cljc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/borkdude/html.cljc b/src/borkdude/html.cljc index 6a4b363..05a5cdf 100644 --- a/src/borkdude/html.cljc +++ b/src/borkdude/html.cljc @@ -43,7 +43,7 @@ (str (name k) "=" (cond (string? v) (pr-str (escape-html v)) (keyword? v) (pr-str (name v)) - (map? v) (pr-str (->css v)) + (and (map? v) (= "style" (name k))) (pr-str (->css v)) :else (pr-str (str v)))))) m)))) ([opts m base-map] From 57a391a581dc43e9a5899d16c3376602cd40b01e Mon Sep 17 00:00:00 2001 From: Jake Zerrer Date: Thu, 11 Jun 2026 08:37:56 -0400 Subject: [PATCH 2/2] Add tests for gating ->css on the style key; changelog entry --- CHANGELOG.md | 5 ++++ src/borkdude/html.cljc | 14 +++++------ test/borkdude/html_test.cljc | 45 ++++++++++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 463931c..3db49bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Unreleased changes are available via `io.github.borkdude/html {:git/sha "..."}` [html](https://github.com/borkdude/html): Produce HTML from hiccup in Clojure and ClojureScript +## 0.2.5 + +- [#16](https://github.com/borkdude/html/pull/16): only render a map attribute value as CSS when the key is `style`; other map-like values such as records now render via `str` ([@telekid](https://github.com/telekid)) +- Fix escaping in cljs when escaped characters appear more than once in string ([@telekid](https://github.com/telekid)) + ## 0.2.4 - Fix attribute value bound to a symbol: `(let [x "blue"] (html [:div {:color x}]))` now resolves the symbol at runtime instead of emitting its name diff --git a/src/borkdude/html.cljc b/src/borkdude/html.cljc index 05a5cdf..8b39b41 100644 --- a/src/borkdude/html.cljc +++ b/src/borkdude/html.cljc @@ -11,11 +11,11 @@ [text] (-> (.. ^String (str text) - (replace "&" "&") - (replace "<" "<") - (replace ">" ">") - (replace "\"" """) - (replace "'" "'" #_(if (= *html-mode* :sgml) "'" "'"))))) + (#?(:cljs replaceAll :clj replace) "&" "&") + (#?(:cljs replaceAll :clj replace) "<" "<") + (#?(:cljs replaceAll :clj replace) ">" ">") + (#?(:cljs replaceAll :clj replace) "\"" """) + (#?(:cljs replaceAll :clj replace) "'" "'" #_(if (= *html-mode* :sgml) "'" "'"))))) (defn ->safe "Implementation, do not use" @@ -43,8 +43,8 @@ (str (name k) "=" (cond (string? v) (pr-str (escape-html v)) (keyword? v) (pr-str (name v)) - (and (map? v) (= "style" (name k))) (pr-str (->css v)) - :else (pr-str (str v)))))) + (and (map? v) (= "style" (name k))) (pr-str (escape-html (->css v))) + :else (pr-str (escape-html (str v))))))) m)))) ([opts m base-map] (let [m (merge base-map m)] diff --git a/test/borkdude/html_test.cljc b/test/borkdude/html_test.cljc index e3de752..bd37ab2 100644 --- a/test/borkdude/html_test.cljc +++ b/test/borkdude/html_test.cljc @@ -3,6 +3,10 @@ [borkdude.html :refer [escape-html html xml]] [clojure.test :as t])) +(defrecord QuestionId [value] + Object + (toString [_] value)) + (defn child-component [{:keys [name]}] (html [:<> "Hello " name])) @@ -85,16 +89,43 @@ (html [:div.container]) "" - (html [:a#foo.bar.baz {:class "quux"}])) - ) + (html [:a#foo.bar.baz {:class "quux"}]) + + "
" + (html [:div {:style {:color :blue}}]) + + "
" + (let [style {:color :blue}] + (html [:div {:style style}])) + + "" + (let [qid (->QuestionId "f33b44d7")] + (html [:input {:type "hidden" :value qid}])) + + "
" + (let [m {:a 1}] + (html [:div {:data-foo m}])) + + "" + (let [qid (->QuestionId "f33b44d7\"\"")] + (html [:input {:value qid}])) + + ;; User dynamically generates a css variable name + "" + (let [i "\"\"" + v (str "--" i)] + (html [:input {:style v}])) +)) (t/deftest test-escaped-chars - (t/is (= (escape-html "\"") """)) - (t/is (= (escape-html "<") "<")) - (t/is (= (escape-html ">") ">")) - (t/is (= (escape-html "&") "&")) + (t/is (= (escape-html "\"\"") """")) + (t/is (= (escape-html "<<") "<<")) + (t/is (= (escape-html ">>") ">>")) + (t/is (= (escape-html "&&") "&&")) (t/is (= (escape-html "foo") "foo")) - (t/is (= (escape-html "'") "'"))) + (t/is (= (escape-html "''") "''")) + (t/is (= (escape-html "\"\"") """")) + ) (comment (ok)