Chapbook automatically converts my straight quotation marks into curly ones!

Im trying to create a cycling link inside a javascript section of a passage. But chapbook converts my straight quotation marks into curly ones, and the string is not interpreted as an insert but just as text.

 let response=`Hello!`;
 let line1 =  `{cycling link, choices: ['Hi!', '`;
 let line2 = response +  `']}`; 
 let line = line1+line2;
 write (line);

The result in the browser:

{cycling link, choices: [‘Hi!’, ‘Hello!’]}

As you see it converts the straight quotations marks into curly ones. And there is no cycling link but just literal text.

1 Like

There might be more ways to implement what you want to do, but here is how to control the options in a cycling link from JavaScript:

engine.state.set('responses', ['Hi!', 'Hello!']); // <== create a proper Chapbook array variable
{cycling link, choices: responses}

This also works and is more native to the way Chapbook works:

otherResponses : ['Hi!', 'Hello!']
{cycling link, choices: otherResponses}

Pages in the Chapbook guide that reflect what I’ve just shown are:

Using JavaScript in Passages
Cycling Links

If you try and generate the raw Chapbook code in JavaScript (as you just were), I don’t believe it renders in the proper order to allow that (JavaScript, then Chapbook). Plus, you get the quotes being altered to opening and closing styles and I’m not quite sure how to avoid that.

1 Like

Could you open a bug for this with a sample story that demonstrates the problem? This sounds like a bug that should get fixed.

Thanks Hall!! I’ll try it! I’m writting the game achivements, and it would be easier for me to group all that data in json format and then parse it into an object in the “Story JavaScript” section. I have tried already and i see my object has global scope. In fact its part of a bigger object that includes tools for parsing text and other utilities. My idea is to keep the passage for text and nice inserts or simple javascript function calls. But i see this approach has it disadvantages. I have read somewhere that it can get messy to work with arrays “hybridly” in javascript and the var section. Should i abandon my original idea? Are there any more known troubles that you think worth mention?

1 Like



The bug is bigger than i thought. It goes far beyond “{cycling link”, or “reveal link” or inserts in general, but whenever you use the command “write” and the string parameter includes quotation marks or apostrophes, you may get all sorts of weird results: from the convertion of quotations to program crash.

I wish I had more experience with Chapbook to answer that confidently.

I definitely like using custom {inserts} and [modifiers] to create an elegant looking story syntax and for presenting clean, readable passage code. I can hide a bunch of generated HTML and JavaScript that way. Make a header insert and just send it the text you want displayed, then you can generate the HTML however you want in JS, for example. I made a stat adjuster that is simply an insert with the name of the variable. It then puts the + and - buttons around it and handles the live updating. Food for thought.

I hadn’t used quotes in variables before so I appreciate you sharing your findings.

I don’t typically use the [JavaScript] modifier in passages for rendering text; I mostly use custom {inserts}. However, you can replace all instances of the " with the &#34; character code. You can use &#39; for ' as well. This seems to work, though it may not be very desirable.

engine.state.set('quotes', '"Quotes"');
engine.state.set('quotesEncoded', '&#34;Quotes Encoded&#34;');

Just tried my old code turning it into an insert, but the straight to curly conversion remained. Then i tried your trick &#39; but, although the quotation marks were then rendered straight, the cycling link was still interpreted as plain text, not as a cycling link. The same goes for reveal link…

I never thought that you could generate proper Chapbook code in the [javascript] modifier with the write() function… as it’s already running the Chapbook code rendering part by rendering the modifier already. However, I am using a rendering process call within Chapbook’s engine that can re-render a code block allowing me the send it any string of code (or a passage for that matter), if memory serves me correctly. I’d imagine you could send it a {cycling link} insert as a full string and all would be well.

I’m not at my computer so I can share that one line of code later if you need it. However, you can do a console.log() of the Chapbook engine and any other objects it uses to see the guts of it all.

And of course, sometimes you have to make a work around too. For example, I made my own insert that captures any key press to continue to the next passage. However, I couldn’t find a function call that actually navigates to a passage (maybe you know of one?)… so I made a [[link]] that was hidden and used JavaScript to simulate a click on the <a> tag.

I believe SugarCube has the most robust support for customization. Snowman is the format to use if you want to make your own engine though, as it has all the basic commands built-in and purposefully accessible to JavaScript. Snowman is intended as a framework first and foremost.

Let us know if you have any other questions.

Here’s what I was talking about before with using Chapbook’s rendering function:

engine.state.set('responses', ['Hi!', 'Hello!']);
write(engine.render('{cycling link, choices: responses}'));

However, that quote problem still persists and renders out:

<a href=”javascript:void(0)” data-cb-cycle-choices=”[“Hi!”,”Hello!”]”>Hi!

However, this shows that the Chapbook code is actually being rendered out. I do wonder is this engine.render() is necessary or if the write() function will render out properly rendered Chapbook code, once the bug is fixed.

I see Chris has responded to your bug report and is on it. That’s fantastic!

I made a custom insert that makes the Chapbook cycling links work.

engine.extend('1.0.0', () => {
  config.template.inserts = [ {
    match: /^> cycling link$/i,
    render() {
      return engine.render('{cycling link, choices: ["Hi!", "Hey!"]}');
  }, ...config.template.inserts ];

And then I just call it with {> cycling link}. You can send it variables, of course, and just modify the insert as necessary. If you are unfamiliar with that process, let me know. Otherwise, this might get you back on track.