Howdy, Stranger!

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

function in Sugarcube?

I'd like to dynamically add tags to passages in Sugarcube, like L's <<addtag>> macro:

http://www.glorioustrainwrecks.com/node/5021

But the macro throws an error for me: "Error: cannot execute macro <<addtag>>: Cannot read property 'tags' of undefined"

Is there a way to do what I want in Sugarcube?

Thanks for reading.

Comments

  • You can pretty easily make a widget to do this. This should work:
    <<widget "addTags">>
    <<script>>
    var args = state.active.variables.args;
    if (args.length < 1) {
    throw new Error("you must provide a passage name");
    }
    else {
    var tags = tale.get(args[0]).tags;
    if (args.length > 1) {
    $.each(args, function(index, tagName) {
    if (index > 0 &amp;&amp; tags.indexOf(tagName) < 0) {
    tags.push(tagName);
    }
    });
    }
    }
    <</script>>
    <</widget>>
  • @mostly useless: What exactly are you trying to accomplish?
  • That's an important question, because the tags you change this way won't be saved between sessions.
  • Thanks for the help! I won't be able to test it out until later as I'm away from my PC right now.

    Here's what I want to achieve: I have a set of background images for various locations in my story. Some passages can be triggered in different locations, so in these passages I'd like to run a script that checks my $location variable and applies the appropriate CSS tag to display the desired image. I'm sure there's a better way to do it, though. :)

    I don't think I need the tags to be saved between sessions, as each of these variable-location passages will only be accessed once in the story.
  • Oh, then you can use this in a script section:
    passage.classes.add("newclass");
    No need to use tags, you can go direct to the CSS class.

    EDIT: Sorry, forgot to add that for this to work, you need this useful bit in your code:
    Array.prototype.add = function (element) {
    if (this.indexOf(element) === -1) {
    this.push(element);
    }
    return this;
    };
  • @Erik Temple: That code won't work with either of the things that passage is likely to be (a passage object or a DOM element).  And you don't want to do either of those here anyway.

    You're spot on about using classes though.


    @mostly useless: If I'm understanding you correctly, you have a set of passages which you can't simply tag with a location tag (e.g. forest), since they're generic passages and could/will be used in multiple locations.

    If that's the case, and assuming that $location contains the name of the location (similar to the passage tags you've used for the same purpose, e.g. forest), then simply do something like this at the very top of each of these location-agnostic passages:

    <<addclass "body" $location>>\
    If $location doesn't simply contain the name of the location, then let me know what $location actually contains and I'll give you an updated example.
  • @TheMadExile: I'm confused by your saying that that code wouldn't work. It's pretty much the only way to implement a change to classes on one passage from another passage. (I assumed that this is why mostly useless was looking to do it with tags rather than by simply changing the class on the body element.)

    @mostly useless: It sounds as though TME has probably figured out what you're needing, but just in case, here's more of my code for context; basically, I'm using the code to manage CSS transitions on both incoming and outgoing passages, so that different transitions can be used to switch to different types of content.
    :: PassageReady
    <<script>>
    var passage = tale.get(state.active.title);
    if (passage.tags.indexOf("sidebar") > -1) {
    //we are going from main flow to a sidebar
    $("#passages").addClass("sidebar");
    $(".passage").addClass("flip");//add class to outgoing passage
    passage.classes.add("flip");//add class to incoming passage
    }
    else if ($("#passages").hasClass("sidebar")) {
    //we are transitioning from a sidebar to the main flow
    passage.classes.add("flip");//add class to incoming passage
    $(".passage").addClass("flip");//add class to outgoing passage
    }
    <</script>>

    ::PassageDone
    var passage = tale.get(state.active.title);
    if (passage.tags.indexOf("sidebar") === -1 &amp;&amp; $("#passages").hasClass("sidebar")) {
    //we are going from a sidebar to the main flow
    passage.classes.purge("flip");
    $("#passages").removeClass("sidebar");
    }
    else if (!$("#passages").hasClass("sidebar")) {
    $(".passage").removeClass("flip");
    }
    [Edited a couple of times for clarity...]
  • There's a difference between working and not bludgeoning you with an error.

    Based on your shown code, passage is a passage object, which means that the classes property is a JavaScript array, which has no add() method.  Unless you or some library you've loaded has modified the Array prototype, adding an add() method, those bits cannot be working.  You may not be seeing an error for various reasons (I assume that code's in PassageReady or something like that), but it has to be throwing an error (likely a TypeError).

    As a test, with your compiled project open in your browser, open the dev console and try something like this (you should see an error):
    SugarCube.tale.get("Start").classes.add("foo");
    Additionally, in that code, at least, you never do anything with the "flip" you're tying to add to the passage object anyway.
  • <<addclass "body" $location>>\
    works perfectly. Sorry I wasn't more specific about what I was trying to do! :D
  • @TheMadExile: Mildly offensive post, sir! I said that the code works perfectly well, because it does. Obviously I added the .add method (I gave the code for it in my previous post), and "flip" is a CSS class, so it does its work through being present or absent.
  • Your first post that I replied to did not originally include your add() method.  You edited that post adding the method only after I had already begun my first reply.

    Honestly, I would have thought my second reply would have made it clear that I didn't know that you'd edited your post.  I wouldn't have said "Unless you or some library you've loaded has modified the Array prototype, adding an add() method", nor would I have suggested that you test for the error.  What would the point of either of those have been (or my second reply at all), if I'd known about your edit.
  • Damnable crossing of posts! But since about 2.5 hours had passed between my edit and your post, it never occurred to me that we could have crossed. I just assumed that in general you were assuming the worst and barely bothering to read the stuff I was writing. (Trust me, it happens all over the web.) And you were doing that to some degree: I may post some stupid stuff some times, but I think I can tell whether code is functional or not! But I also was assuming the worst in thinking that you had seen the .add() edit and were just ignoring it. I call us even!
  • Sorry to drag this up again. I need to use addclass to add one specific class as well as the variable.

    I checked the Sugarcube documentation and tried things like:
    <<addclass "body" "whatever" $location>>
    But I can't seem to get the syntax right and only the variable class is being added.

    Thanks for reading!
  • Currently, you'll have to do it like this:
    <<addclass "body" $location>><<addclass "body" "whatever">>\
    The class_names argument expects a space delimited list of class names, which you can't easily do here since you have a $variable and a string literal that you want to use.
  • Awesome, thanks. Is there a way to apply a class to links, passages, anything where that class has an effect, without specifying each bit at a time?
  • Yes.  The selector argument of all of the DOM macros can be used to specify a group of selectors as easily as one (and in either case can be used to select multiple elements, which is a bit of a double edged sword).  As with jQuery or <Element>.querySelector(), you separate multiple selectors with commas.

    For example:

    <<addclass "body, .pie" $location>>
    That would add the class(es) specified by $location to both the body element and all elements containing the class "pie".
  • Sweet! Thanks. ;D
Sign In or Register to comment.