[Snowman 1.3] Crazy problem with HTML and scripts

Does this make any kind of sense? Using Snowman 1.3, as in the twinery.org online editor:

<script>console.log("Hello world")</script>

Works! :+1:

<p><% console.log("Hello world") %></p>

All great! :heart_eyes:

<p><script>console.log("Hello world")</script></p>

:warning: SyntaxError: expected expression, got '&'

What the whatting?

Is this simply a bug? A feature? It gets better.

<script>console.log("Hello world")</script>

Missing the closing tag and making it into different lines, it works again! But

<p><script>console.log("Hello world")</script>

Missing the closing tag but putting all in the same line, it dies screaming again!

The story I’m working on is HTML heavy. Very. Plus lots of inline scripts and rendering one passage inside another. I don’t think I have any fireproof way of preventing the tag combinations that kill the game. And I must use script tags instead of <% %>, since the latter doesn’t work once the passage finishes rendering.

Can anything be done about this madness? Thanks.

You should report this behaviour on the Issues page of the Snowman project’s repository, as you may of found a bug or unintended behaviour.

One thing to note is that the purpose of the <p> element is to format Textual content (or related elements) as a paragraph, and as the <script> element is definitely not textual content it structurally doesn’t make sense to embed it within a paragraph element.

There are two reasons your 4th example (the one with the missing </p> tag) works:

  1. The line-break after the <p> open tag indicates that is the end of a ‘line’ of continuous content, and Snowman automatically wraps each ‘line’ of continuous content within a <p> element.
  2. The web-browser you’re viewing the generated HTML document in notes a unpaired start tag and automatically add the required end tag to the Document Object Model it is generating for the page.

So the HTML generated for your 4th example ends up looking something like the following

<script>console.log("Hello world")</script>

As the maintainer of Snowman, I’ll look into this. However, @Greyelf is right about both the tag completion and the reporting. Please submit issues like this on GitHub so I can look into them and fix them going forward.

And I must use script tags instead of <% %>, since the latter doesn’t work once the passage finishes rendering.

Any included template code is the first thing processed in a passage. It won’t work after the passage is rendered because it already has. If you want to re-process something, you can use <script> tags and call window.passage.render() and pass it additional text to render.

For example, you can do the following:

window.passage.render('<% console.log("Hey! Listen.")  %>')

If, as you note, you have lots of HTML, you can also break up the Underscore template code and use conditional statements to optionally display things. Consider the following example.

You see a chest here in the hallway.
<% if (!s.chestOpen) { %>
Do you want to open it?

[[Open the chest.|chest]]
<% } else { %>
It's open, and there's nothing inside.
<% } %>

Something else to consider is using print() to “write” to a passage while within templated code blocks.

Thanks to both. I wasn’t aware of the bug tracker, I’ll report that now.

I should note that the p tags were what I happened to have as an example, but the problem also happens with div tags. My exact problem is this: I explicitly define an HTML div with some content. Within that block, I render another passage* with story.render(). That passage includes some script block: that block is now within the div defined in the original passage, and that’s when the thing breaks. Like this:

:: a
<div>   <%= story.render("b") %>   </div>

:: b

In other situations, I can simply write all scripts outside HTML blocks, but when another passage is embedded I lose control of that. My only solution would be renouncing to use story.render() inside HTML blocks. I would lose layout options (this story is all about layout and heavy design) but at least it would work.

* And this is why I use script tags instead of <%. I have to embed a passage with story.render() long after the passage is rendered, in response to a player clicking a choice.