Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

[Snowman] story.render failing

edited February 2017 in Help! with 2.0
I apologise for asking this since I know very little Javascript to work with Snowman, but I've done great advances porting my Harlowe game to Snowman.

I have these two passages:
::render
<%= story.render("content") %>

::content
<a style="color:red" id="hook">Link</a>
<script>
	$('#hook').click(function () {
			story.show("render")
		})
</script>

You run ::render, it displays ::content, with a link that when clicked runs render again. It works perfectly.

Now change ::content like this:
::content
<a style="color:red" id="hook">Link</a>
<script>
	$('#hook').click(function () {
			story.show("render")
		})
</script>

Some other text.

And now, the story.render() function fails with an Unexpected token message.

Can you tell the reason for this? My final goal is building a loop that renders several passages like ::content next to each other, but it fails because printing anything after the </script> tag breaks something with story.render.

Thanks!

Comments

  • edited February 2017
    The simple answer is to move the script element to the end of the passage.

    warning: your Javascript is missing two semi-colons and is relying on the web-browser's parser to add them, this is not a good idea because it could get it wrong.

    Try the following:
    :: content
    <a style="color:red" id="hook">Link</a>
    
    Some other text.
    <script>
    $('#hook').click(function() {
    	story.show("render");
    });
    </script>
    

    note: In Twee Notation there is generally a space character between the double colons (::) and the Passage Name.
  • You're attempting to select content which may not be on the page yet. The best thing to do would be wrap your code in Snowman's special jQuery-ready-style callback, which is executed after passage render. For example:
    <a style="color:red" id="hook">Link</a>
    <script>
    	$(function () {
    		$('#hook').click(function () {
    			story.show("render");
    		});
    	});
    </script>
    
    Some other text.
    

    From Snowman's documentation:
    $, which acts like jQuery's $ method but with one exception. If you pass it a single function, this function is run when the passage appears onscreen, with it bound to the passage DOM element.
  • edited February 2017
    Thanks @greyelf and @TheMadExile but both suggestions don't work, I had tried them before in fact.

    More specifically, I can't move the script to the end of the passage because in the real game (this is an example) I story.render a series of passages, each one being a link and a script.

    What my game does is: I have multiple room passages. I have an array for each room with the choices each room offers at that moment of the game. Each choice is a passage like the one here: a link and the actions run on clicking the link. Those choice passages get story.rendered one after another, so the result is like this example: text + script + text + script + text + script.
  • Menti wrote: »
    Thanks @greyelf and @TheMadExile but both suggestions don't work.
    ...
    so the result is like this example: text + script + text + script + text + script.
    Just to make sure, you're basically describing something like the following except using content stored in collections instead of hard-wire information:
    :: Start
    <% s.counter = 0 %>
    [[render]]
    
    :: render
    <% s.counter += 1 %>counter: <%= s.counter %>
    <%= story.render("content1") %>
    <%= story.render("content2") %>
    
    :: content1
    <a style="color:red" id="hook1">Link</a>
    
    This is the content1 passage.
    <script>
    $('#hook1').click(function() {
    	story.show("render");
    });
    </script>
    
    :: content2
    <a style="color:red" id="hook2">Link</a>
    
    This is the content2 passage.
    <script>
    $('#hook2').click(function() {
    	story.show("render");
    });
    </script>
    
    ... because the above works correctly using Snowman v1.3.0


    So does the following example which uses TheMadExile's solution.
    :: Start
    <% s.counter = 0 %>
    [[render]]
    
    :: render
    <% s.counter += 1 %>counter: <%= s.counter %>
    <%= story.render("content1") %>
    <%= story.render("content2") %>
    
    :: content1
    <a style="color:red" id="hook1">Link</a>
    
    This is the content1 passage.
    <script>
    	$(function () {
    		$('#hook1').click(function () {
    			story.show("render");
    		});
    	});
    </script>
    
    :: content2
    <a style="color:red" id="hook2">Link</a>
    
    This is the content2 passage.
    <script>
    	$(function () {
    		$('#hook2').click(function () {
    			story.show("render");
    		});
    	});
    </script>
    
  • @Menti did you try adding the semi-colon that @greyelf suggested?
  • edited February 2017
    @greyelf thanks. You have understood perfectly my goal. Your first proposal renders fine the first time, but after clicking on any link I get an unexpected token failure. I'm using Snowman 1.2 however, I'll try to update.*

    @Rokiyo yes, I added the suggested semicolons.

    I can add that in my first test I wrote the script within underscore's <% %> instead of <script> tags, and the link simply didn't do anything when clicked.

    * I tried to update Twine when the new version came out but I ran into a problem with the permissions for the working files folder (on Linux), and Twine couldn't save anything. Actually it doesn't create a Twine document folder. I'll have another go.
  • Menti wrote: »
    I can add that in my first test I wrote the script within underscore's <% %> instead of <script> tags, and the link simply didn't do anything when clicked.
    That's because you need to use Snowman's post-display callback—or the equivalent—to make that work, as I explained previously.

    When I made my original post, I overlooked the fact that you were using a <script> tag, rather than <% … %>—because who does that. You should definitely be using <% … %>, rather than a <script> tag. In particular, the $(function () { … }) is Snowman's post-display callback within <% … %>, but will be jQuery's ready callback within a <script> tag—which, as I've posted numerous times, is patently worthless when used within a story format. Additionally, the special s alias variable, also only works within <% … %>.

    Beyond that, Twine 2 v2.0.11 came preinstalled with Snowman 2 v1.3.0—v1.2 last appeared in Twine 2 v2.0.10. Exactly which version of Twine 2 are you using?


    Anyway, I downloaded Twine 2 v2.0.10, extracted Snowman 2 v1.2 from it and installed it into Twine 2 v2.1.0. I then tested the following code, which performed exactly as expected:
    :: Start
    <% s.counter = 0; %>[[render]]
    
    
    :: render
    <% s.counter += 1; %>counter: <%= s.counter; %>
    <%= story.render("content1"); %>
    <%= story.render("content2"); %>
    
    
    :: content1
    <a style="color:red;" id="hook1">Link</a>
    
    This is the content1 passage.
    <%
    	$(function () {
    		$('#hook1').click(function () {
    			story.show("render");
    		});
    	});
    %>
    
    
    :: content2
    <a style="color:red;" id="hook2">Link</a>
    
    This is the content2 passage.
    <%
    	$(function () {
    		$('#hook2').click(function () {
    			story.show("render");
    		});
    	});
    %>
    
  • edited February 2017
    Thanks @TheMadExile! It almost works: your exact code gave me an Unexpected Token ; failure, that I solved by deleting the ; characters between <%= ... %> in ::render.

    It seems that I can move forward now. Thanks again! I apologise again for asking this kind of things, but something like "post-display callback" is beyond my Javascript knowledge.

    It's Twine 2.0.10 I'm using. I wasn't aware of 2.0.11 since I really use twee2 instead of Twine, and I've failed to make 2.1 work.
Sign In or Register to comment.