reagent

Pepijn de Vos 2023-12-03T20:23:10.489989Z

What would be the best way to inject raw JSON into the DOM? My current idea is to do [:script#document {:type "application/json"} (.getText document)] and then do (defonce document (.-innerText (.getElementById js/document "document"))) but this leaves me with html escapes in the JSON. So I either need to unescape them or just not escape them in the first place.

2023-12-04T20:11:18.477609Z

You might need to escape JSON anyway if it contains user data. For example, a string could contain </script> which would close the script tag and the rest of JSON would be part of HTML. HTML encoding and decoding of JSON should be straightforward.

p-himik 2023-12-04T20:59:37.485249Z

Either it's a valid JSON that contains </script> in a string, or it's an invalid JSON. In the former case, it's not a problem. In the latter case, you have other problems. :)

2023-12-04T21:04:35.728719Z

This is not true. When a browser parses HTML, it encounters starting <script> tag and then it scans till it finds a matching </script> tag. It does not care whether JSON is valid or not. For example, see https://stackoverflow.com/questions/39193510/how-to-insert-arbitrary-json-in-htmls-script-tag. I had a similar issue in OrgPad code, where we store document data inside script tag using transit+json. Originally, we did not escape it, till one user was creating a document about HTML and JS, and it was loaded broken since the document contained the string </script> somewhere.

2023-12-04T21:19:58.242759Z

Decoding HTML encoded strings is straightforward, for example using the following code:

(def ^:private escape-sequences-dict
  "A sequence of pairs which are applied in the order from  left to right
  when replacing escape sequences with escaped characters and in the
  opposite order for the opposite conversion."
  [["<" "<"] [">" ">"] [""" "\""]
   ["'" "'"] ["'" "'"] ["&" "&"]])

(defn decode
  "Replaces escape sequences with escaped characters, so original string can
  be recovered from HTML."
  [s]
  (reduce (fn [string [escape replacement]]
            (str/replace string escape replacement))
          s escape-sequences-dict))

(defn encode
  "Replaces escaped characters in a string with their escape sequences,
  so they can be safely inserted inside HTML."
  [s]
  (reduce (fn [string [escape replacement]]
            (str/replace string replacement escape))
          s (reverse escape-sequences-dict)))

p-himik 2023-12-04T21:27:09.979439Z

Oh, huh... Thanks for correcting my understanding. Perhaps some escaping is due.

2023-12-04T21:30:02.475029Z

I was surprised by that a few months back as well 🙂.

p-himik 2023-12-03T21:47:43.592849Z

Hold on, what do you need to escape? JSON doesn't have anything that would interfere with HTML. I just tried adding [:script {:type "application/json"} "{\"hello\": \"there\"}"] to a page, in the DOM it looks like <script type="application/json">{"hello": "there"}</script> - nothing is escaped.

Pepijn de Vos 2023-12-03T21:52:29.984989Z

well

(rdom/render-to-static-markup [:script {:type "application/json"} "{\"hi\":3"])
"<script type=\"application/json\">{&quot;hi&quot;:3</script>"

p-himik 2023-12-03T21:58:35.235009Z

Weird, seems that that function works differently from what React does in its regular mode. Also, on my end I get < turned into \x3C. But why do you need that function? I don't think I've ever seen it being used.

Pepijn de Vos 2023-12-03T22:01:41.458129Z

To generate HTML in a vscode extension to ship to the frontend. Seemed nicer than rawdogging strings but then I guess I just defeated any added security by dangerously setting innerhtml

p-himik 2023-12-03T22:03:54.379989Z

Hmm. Seems like it's exactly what you're supposed to do: https://github.com/facebook/react/issues/4446#issuecomment-123417310 Albeit the comment is from 8 years ago. But given that you know that the content is JSON (BTW you missed } in the example), you can build the string by plain concatenation - no need for React here at all.

p-himik 2023-12-03T22:05:10.615619Z

I do a similar thing when I need to deliver complex static payload with HTML that can't be a part of the JS bundle, albeit I use Selmer or Hiccup and Transit instead of JSON.

Pepijn de Vos 2023-12-03T22:21:24.856809Z

Fun