sinedied / backslide

:sweat_drops: CLI tool for making HTML presentations with Remark.js using Markdown
https://sinedied.github.io/backslide
MIT License
764 stars 50 forks source link

Javascript references in code blocks break presentation #51

Closed jldiaz closed 5 years ago

jldiaz commented 5 years ago

OS

MacOS Mojave, 10.14.2

Problem

When one document contains code blocks in html which contain <script> tags, the presentation cannot be visualized.

The following presentation.md

# Example code:

```html
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

Results in a `presentation.html` after `bs export --no-inline`,  which contains:

```html
  <script>function create() {
      return remark.create({
        source: "# Example code:\n\n```html\n<script src=\"https://code.jquery.com/jquery-3.3.1.min.js\"></script>\n```\n\n",
        ratio: '16:9',
        highlightLines: true,
        countIncrementalSlides: false,
        highlightStyle: 'github'
      });
    }
 </script>

It looks correct, but the browser (Chrome) complains about presentation.html:27 Uncaught SyntaxError: Invalid or unexpected token (line 27 is the one containing source: "..."). I noticed also that all editors I tried on this file (vim, VS Code), also produced bad syntax highlighting on that line and a warning about "unterminated string literal", but I'm unable to see what is wrong.

Apparently, the browser considers the </script> inside the source attribute as the closing tag for <script>function create()... As a result, create() is not properly defined and the presentation looks like this:

image

Expected Result

A presentation showing the example code.

As a workaround I can change <script></script> in the example by something which looks similar, for example <scipt></scipt>, or, being mischievous <sсript></sсript> in which I replaced ASCII c by cyrillic small letter es с (U+0411) which looks identical.

This makes the problem vanish. The resulting presentation.html contains now (after bs export --no-inline):

  <script>
    function create() {
      return remark.create({
        source: "# Example code:\n\n```html\n<sсript srс=\"https://code.jquery.com/jquery-3.3.1.min.js\"></sсript>\n```\n\n",
        ratio: '16:9',
        highlightLines: true,
        countIncrementalSlides: false,
        highlightStyle: 'github'
      });
    }
  </script>

Which even if it looks indentical to the first case, (but with the c replaced by cyrillic) it does not produce any error in the browser nor the editors tried. The resulting page now renders fine:

image

jldiaz commented 5 years ago

I think this problem is not exactly due to backslide, but the way in which backslide embeds the markdown in the html, as a string passed in the attribute src, which causes the problem because it is (apparently) not properly quoted.

Perhaps backslide could embed the markdown inside the body of the html document, in a <textarea id="source">, instead of passing it as parameter to remark.create().

jldiaz commented 5 years ago

Ok, I figured out what the problem was.

Apparently, you cannot have the sequence of chars <, /, s, c, r, i, p, t, > inside a <script> block in HTML, because that would end the script block, even if that squence is quoted.

In other words, this is not valid HTML:

<html>
  <head></head>
  <body>
    <script>
       var v = "</script>";
    </script>
  </body>
</html>

A workaround for this problem is to "break" the conflictive sequence of chars. For example:

    <script>
       var v = "<" + "/script>";
    </script>

This way the variable v has the same value, but the html is now valid.

I think this approach can be easily used in backslide. I'm preparing a PR.

sinedied commented 5 years ago

Sorry for the delay, a fix is already present in the feature/refactor branch (that's taking way longer that I imaged to finish), see https://github.com/sinedied/backslide/issues/43

You can use it in the meantime by cloning this repo, then:

sinedied commented 5 years ago

Fixed in 2.3.3 😉