1

I am having trouble pulling in end-of-page scripts (or other content) from my layout file after making the call for '@content.' I am using coffeekup templating and have the following default.html.coffee layout file.

doctype 5
html ->

  head ->

    meta(charset:"utf-8")
    title("Docpad")
    if @document.description?
      meta(name:"description", content:@document.description)

    stylesheets = ['/styles/app.css']
    @getBlock('styles').add(stylesheets).toHTML()

  body ->

    div class:"row", ->
      div class:"large-12 columns", ->
        h1(class:"docs header", "Header")
        hr()

    @content
    @getBlock('scripts').toHTML()

The problem I'm running in to is that '@content' correctly yields and renders page-specific content only if nothing follows it (if the @getBlock('scripts') line above, for example, is removed or commented out). With the above code, however, the getBlock call for scripts succeeds but '@content' does not insert content. Any help appreciated, Thanks.

8ken
  • 15
  • 4

1 Answers1

1

Let's take a look at the compiled javascript of your code there. We can use the compiler on coffeescript.org to do this:

doctype(5);

html(function() {
  head(function() {
    var stylesheets;
    meta({
      charset: "utf-8"
    });
    title("Docpad");
    if (this.document.description != null) {
      meta({
        name: "description",
        content: this.document.description
      });
    }
    stylesheets = ['/styles/app.css'];
    return this.getBlock('styles').add(stylesheets).toHTML();
  });
  return body(function() {
    div({
      "class": "row"
    }, function() {
      return div({
        "class": "large-12 columns"
      }, function() {
        h1({
          "class": "docs header"
        }, "Header");
        return hr();
      });
    });
    this.content;
    return this.getBlock('scripts').toHTML();
  });
});

Notice how this.content is just a non-actionable statement. Just as if I did this: "a"; "b"; "c"; "d" nothing would do anything.

The usage, or intention of the code you've povided seems to imply a misunderstanding of the way either CoffeeKup or CoffeeScript works, so let me evaluate what's going on and why sometimes it works and sometimes it doesn't.

When we do div -> "blah" it comiles to div(function(){return "blah";}) which says pass div a function that when called will return the string blah. Now CoffeeKup knows that any strings returned to it it should render for convenience. But as we can't return multiple things (as the first return exists the block), what are we to do?

CoffeeKup provides the text function, allowing us to do:

div ->
    text "a"
    text "b"

Which when compiled looks like:

div(function() {
  text("a");
  return text("b");
});

Which is just what we want, as the text call, just like div and all the other element calls, doesn't return a string and outputs the content directly.

So all in all, the solution is to prefix:

@content
@getBlock('scripts').toHTML()

With the text call, so it becomes:

text @content
text @getBlock('scripts').toHTML()

If you ever want to escape the HTML entities (so convert < to &lt;) then you'll want to add the h call as well like so h "content to be escaped" and combined with text will look like text h "content to be escaped" - however that is just something to note, not something you need right now or here.

balupton
  • 42,415
  • 27
  • 116
  • 167
  • Sweet! If it solved the problem, be sure to mark the answer as the accepted answer by clicking the checkmark next to it so people know the problem is solved. More info here: http://meta.stackexchange.com/a/5235/149978 – balupton Jul 07 '13 at 19:05