Howdy, Stranger!

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

SugarCube: Calling state.display from macro in Start

edited January 2014 in Help! with 1.x
I would like to be able to move the story to a new passage from ::Start based on the content of a URL query string; I check the query string at startup for "nav=" at startup, and if there is a passage name provided, I want to skip directly to that passage, without further user input. I am trying to do this with a new widget or macro that simply invokes state.display, but the story doesn't forward to the new passage, it merely clears the passage area. This code works:
<<link "Click here" $urlopts["nav"]>>
but this does not:
<<goto $urlopts["nav"]>>

:: Goto Passage [script]
(function () {
macros.add("goto", {
handler: function () {
try {
state.display(this.args[0]);
}
catch (e) {
return this.error("Go to passage: " + e.message);
}
}
});
}());
The macro code doesn't throw any visible error messages, but I messed around a bit with wrapping it in a <<click>> and was able to see a message "This passage does not exist". So, it seems as though the problem is that while <<link "Click here" $urlopts["nav"]>> can properly parse the value stored in $urlopts["nav"], my <<goto>> macro cannot.

What am I missing here?

EDIT: The <<click>> construction I mentioned above went like this:
<<click "Click here to go to " + $urlopts["nav"]>><<goto $urlopts["nav"] >><</click>>
This wasn't able to set the link text from $urlopts["nav"] either, so I'm wondering if there is simply something else I need to do when passing that sort of value into custom macros...?

Comments

  • What you want to be alerting or console.logging is state.active.variables.urlopts to do some troubleshooting. The state.display appears to be working from your explanation, its the argument you want to look at. It could be trying to send you to a passage called 'undefined' or several other things.

    I'm not sure but that's where I'd start.
  • No, as I explained, the argument is fine. It works exactly as expected when passed into <<link>>, but not when passed into my own macro or as text to be output to screen by <<click>>.
  • I realized that. My idea was simply to find out why it's not working. Passage does not exist. Okay. Well where is the macro trying to send you? Is this a situation where you need to take into account Sugarcube's classname normalization?
  • It clears the passage area to move on from ::Start, but never loads the new passage. The .passage section is never loaded with a new passage's information. Here's the relevant HTML after the state.display:
    <section id="passage-start" class="passage nosave" data-passage="Start" style="visibility: visible;">
    <header class="header"></header>
    <div class="body content"></div>
    <footer class="footer"></footer>
    </section>
    Normally, if you call state.display without interaction and attempt to invoke a nonexistent passage, the existing passage does not clear, and the "passage does not exist" message is shown. So it's not acting precisely as it should. This could be partially due to running from ::Start, perhaps. And in fact, if I include teh <<goto>> macro in any other passage and pass it the same argument, I get this message: Error: <<goto>>: Go to passage: Cannot read property 'title' of undefined, which suggests that it isn't quite being processed as a non-existent passage... (The title property, of course, is not in my code directly, it is being called by library code.)
  • Erik wrote:
    I would like to be able to move the story to a new passage from ::Start based on the content of a URL query string; I check the query string at startup for "nav=" at startup, and if there is a passage name provided, I want to skip directly to that passage, without further user input.

    You cannot use state.display() to display a new passage while in the middle of displaying another.

    Erik wrote:
    EDIT: The <<click>> construction I mentioned above went like this:
    <<click "Click here to go to " + $urlopts["nav"]>><<goto $urlopts["nav"] >><</click>>
    This wasn't able to set the link text from $urlopts["nav"] either, so I'm wondering if there is simply something else I need to do when passing that sort of value into custom macros...?

    <<click>> does not accept expressions, so you effectively passed it three arguments (1: "Click here to go to ", 2: "+", 3: $urlopts["nav"]).
  • Is there some reason why using the Start passage as a router is unpalatable?  For example:

    :: Start
    <<display $startPassage>>

    :: Default Start
    This is the default starting passage. Blah blah....
    At startup you'd set $startPassage either to the real "start" passage ("Default Start" in the above example) or to $urlopts["nav"].
  • TheMadExile wrote:

    Is there some reason why using the Start passage as a router is unpalatable?

    Just doing a <<display>> from ::Start doesn't call PassageReady for the new passage, which I need it to do.

    It sounds like I should be able to forward using state.display() from ::PassageDone, though, so I'll plan on doing that, something like this:
    ::PassageDone
    <<script>>
    if (state.active.title === "Start" &amp;&amp; state.active.variables.urlopts.hasOwnProperty("nav")) {
    state.display(state.active.variables.urlopts["nav"]);
    }
    <</script>>
  • Erik wrote:
    Just doing a <<display>> from ::Start doesn't call PassageReady for the new passage, which I need it to do.


    Ah.  I would have thought that you could fix that with a little extra logic, I mean you do know which passage it's supposed to be after all, but maybe you're doing something really complicated in there.

    Erik wrote:
    It sounds like I should be able to forward using state.display() from ::PassageDone, though, so I'll plan on doing that,


    That's not going to work either.  Both methods of doing pre-/post-render tasks (SugarCube's PassageDone/PassageDone passages and the prerender/postrender task objects, which SugarCube also supports) are called within the bounds of state.display().

    I suppose that I could add a configuration property for the starting passage, which would default to Start, but that you could change st startup (probably something like config.startPassage).
  • Yeah, you're probably right--I could probably either repeat (or wrap in a function) the functionality from PassageStart and call it on the upcoming passage before <<display>>ing it.

    Another options would be a timed version of the goto macro, that would go there after a timeout, but that feels hacky to me.
  • Erik wrote:

    Yeah, you're probably right--I could probably either repeat (or wrap in a function) the functionality from PassageStart and call it on the upcoming passage before <<display>>ing it.


    Well, as I said, I can add a configuration property for the starting passage, if what you'd have to do otherwise is a bother.  I mean, it's general enough that I don't have any reservations about adding it.

    Erik wrote:
    Another options would be a timed version of the goto macro, that would go there after a timeout, but that feels hacky to me.


    That's because it is. :)
  • Yeah, I think a config for the Start passage would be good, not only because it would help make this particular situation easier, but because it seems a little constraining to have to use a passage called "Start"...
  • A new SugarCube release has been published which addresses this issue.
  • Thanks for this!
Sign In or Register to comment.