Javascript interop problem

Hello, I am using the code below in a Phoenix template to render Asciidoc text:

      <script>
        var asciidoctor = Asciidoctor();
        var render_asciidoc = function() {
            var content = `<%= Phoenix.HTML.raw(@text) %>`
            document.getElementById('asciidoc').innerHTML = asciidoctor.convert(content.replace( /!!aWz!!/g, '`'));
         }
     </script>

The line

var content = `<%= Phoenix.HTML.raw(@text) %>`

slurps up text furnished by Phoenix whereupon asciidoctor.convert (in a .js package) renders the text and places it in the right spot on the page. Unfortunately the line var content ... is not reliable. For some content, the content becomes incorporated in the code … so it seems from inspecting the console … I see things like this:

 <script>
        var asciidoctor = Asciidoctor();
        var render_asciidoc = function() {
            var content = `:toc:

== Introduction

For other content, the above cod works just fine. I haven’t been able to isolate the properties of the offending content. In any case, I need code that won’t be content-dependent. Any idea what’s going on here?

Perhaps there is a better way of getting the content from Phoenix to Javascript?

The template literals you are using do support interpolation, therefore if you happen to have literal ${...} in your ASCIIdoc document, you might get garbled output there, also you’ll produce invalid JavaScript, when there is a literal backtick in the document.

Since \ is treated literally in template literals, I’m not sure if you can use a backtick in a template literal.

If I were you, I’d replace "\n" by "\\n" and "\"" by "\\\"" when inserting while using good old double-quoted string literals in your JavaScript.

But, this is only a rough guess, since you haven’t shown us the input that lead to your output.


PS and edit: I’ve currently no elixir or phoenix environment at hands where I could check if I have the correct level of escaping, you’ll need to check on your own if you have to add or remove some backslashes in my proposal.

2 Likes

Thanks! It was the $ (for LaTeX) in the text that was creating the problem. I now do these mappings before sending to Javascript:

text
    |> String.replace("`", "!!BT!!")
    |> String.replace("$", "!!DOL!!")
    |> String.replace("\\", "\\\\")

Then invert the first two on the JS siide:

content = content.replace( /!!BT!!/g, '`').replace(/!!DOL!!/g, '$')

Sometimes the “brute force” way of getting past these types of issues is to Base64 encode in the source environment:

iex(1)> Base.encode64("foo © bar 𝌆 baz")        
"Zm9vIMKpIGJhciDwnYyGIGJheg=="
iex(2)> 

and then to Base64 decode in the target environment.

1 Like

I still think using double quotes on the JS side and escaping properly when injecting the text were the better idea, since it does not add any computational overhead to your client. Also when I googled for template literals yesterday, there still were compatibility warnings.

Also problems may arise when your author wants to place a literal !!BT!! or !!DOL!! in the text.

Implementing proper escaping for doublequoted string might be easy as dumping your input string into a JSON-encoder, which you probably have as a dependency already :wink:

1 Like

Thankyou! I will implement this better suggestion. Much appreciated.