Friday 7 March 2014

Prerender and postrender in Twine

Twine supports things called  prerender and postrender. I was hoping to use postrender to blank lines between paragraphs. It will not do that (still not found a way for that), but I learn a few things a long the way.

This may well depend on which format you are using; this is based on Sugarcane.
Sugarcane has a content variable that is set like this when a page is being displayed:

var content = insertElement(passage, "div", null, "body content");

I guess content is an XML node.

It then goes through all the prerenders defined, calling each one in turn, with the content variable. I do not know what that order is, but I guess it is the order they are defined in, though what that means in Twine is not clear.

What prerender does is add nodes to content. To me, prerendering would be some kind of manipulation; what this is doing is prepending. This is a way to add a title to the top of every page, not a way to modify the text.

Next, the passage text is added to content:

new Wikifier(content, this.processText());

I would guess that this.processText() gets the text for the current passage and does some kind of processing. This is then "wikified", which presumably converts the Wiki conventions (eg //) to HTML (eg <i>), etc. This all gets added as new nodes for content.

Then any postrenders are called. Again, this is really just appending nodes to content, not postrendering in its normal sense.



Postrender and prerender are just functions that are defined as normal, something like this (in passages tagged as "script"):

prerender.myname = function(content) {
  new Wikifier(content, "This is my title\n");
}

postrender.myname = function(content) {
  new Wikifier(content, "This is my footer");
}

Note that the functions have to be attached to the postrender and prerender objects. This ensures Twee can find them.

You can call them anything you like, I have chosen "myname"; you can also call content anything you like, as long as you are consistent within a function. Note that the text in the prerenderer ends "\n", this ensures the title goes on its own line. This is not necessary for the postrenderer. You can put all the normal formating codes into the text, and use JavaScript to build up complex strings to be added.


Here is a neat postrenderer that adds footers to pages. A page tagged as "footer" contains the text to be added. Any page that shares a tag with a footer passage gets that footer added.
http://twinery.org/forum/index.php?topic=672.0

postrender.tagFooter = function(content) {
    var i,j, feet = tale.lookup("tags", "footer");
    for (i = 0; i < feet.length; i++) {
        for (j=0;j<this.tags.length;j++) {
            if (!feet[i].tags.indexOf(this.tags[j])) {
                new Wikifier(content, feet[i].processText());
            }
        }
    }
}

Addendum

It turns out that you can use postrender to manipulate the content of the page, as I found from this forum thread. This only seems to work in Sugarcube by the way.


function processTextNodes(node) {
  if (node.nodeType == 3) { // text node
    node.nodeValue = node.nodeValue
      .replace(/story/g, 'tale');
  } else {
    for (var i in node.childNodes) {
      processTextNodes(node.childNodes[i]);
    }
  }
}

postrender.subst = function(content) {
  processTextNodes(content);
}


All the postrender function, subst, does is call another function processTextNodes. This is a recursive function that works through the XML structure. The bit that does the work, and that you will want to modify, is in blue. In this case, all it does is swap the "story" for "tale". The important value you will be using is node.nodeValue which is just a string contenting a single paragraph of your passage.



I still could not use this to add extra lines; searching for both /\n/ and /<br>/ failed to find any matches, and this is when I realised that each line (in the JavaScript sense; each paragraph in Twine) is stored as a node. Adding to the end of a line is easy enough:

node.nodeValue = node.nodeValue + "<br>";

Unfortunately, this just shows  "<br>" at the end of a line, rather than giving an extra line. Adding "\n" had no effect.




2 comments:

  1. prerender.myname = function(content) {
    new Wikifier(content, "This is my title\n");
    }

    How would you be able to output the passage name itself into that code? and have it centered? (for Sugarcane). Is it possible?

    ReplyDelete
    Replies
    1. The name of the passage can be accessed with state.active.title. You can use it in a prerender like this:

      prerender.myname = function(content) {
      new Wikifier(content, "<center>" + state.active.title + "</center>\n");
      }

      Delete