Content

We've seen how you can generate content by rendering templates in URLs, Views and Middleware. It is entirely possible to build a web application using templates alone – which is how most web frameworks work. The downside of templates is that they can become difficult to maintain as the project grows. Making a seemingly simple change tends to involve editing a number of files, and increases the chance that you will break something on some other page. Moya offers a complimentary system called content that makes generating HTML in a web application a less brittle process.

Consider some kind of corporate site, which is the bread and butter for many developers. Your client has asked you to put a news ticker widget on the front page, which pulls news items items from the database. You implement this by adding some parameters to the template which generates the page, and including a template to generate the widget markup. You also add markup on the main page to pull in the CSS and Javascript that makes it work. Your client is happy for a few weeks, but comes back to request that you show a news ticker on another page, with news from a different source. So you modify the view for the new page to generate the appropriate parameters, and modify the other template to include the widget markup, JS, and CSS. Even if you were to factor out common elements and follow best-practices, you've still done work twice. And the problem only gets worse if your client wants yet another new ticker elsewhere.

This is one of issues that Moya's content system is intended to solve. With content, you can implement the news ticker with the usual web development technologies. Only now you can add a news ticker to another page with a single line change that automatically generates the markup and pulls in the JS and CSS needed to make it just work. Leaving you plenty of time to invoice the client and go back to playing Minecraft.

Defining Content

A content definition is a high level description of a page which Moya will use to generate markup. Content consists of a number of independent sections containing nested elements.

Lets look at an example of a content definition. The following might be used to render an index page, which lists all available sushi products:

<moya>
    <content libname="content.product.list" template="product-list.html">
        <title>Sushi Product Page</title>
        <section name="body">
            <for src="products" dst="product">
                <node template="product.html" let:product="product"/>
            </for>
        </section>
    </content>
</moya>

The following code will render the content:

<render-content content="#content.product.list" dst="html">
    <let products="['nigiri', tuna-roll', 'fugu']"/>
</render-content>

The code inside <content> is executable Moya code; when invoked (with <render-content>) Moya will execute the content line by line and build up an internal description of the page, known as a content object. This content object may then be rendered with a template to create the HTML that will be served.

The first tag inside the <content> tag is <title>, which sets the title to "Sushi Product Page". Next there is a <section> tag which marks a block of renderable elements. A section defines content for a particular part of a page; such as the body, a column, footer, etc. In our example we have a single section called body which contains a <for> loop that calls <node> for each item in the products list. The <node> tag associates data with a template, so the content will contain a reference to a template for each item in products.

When the <content> tag returns, Moya now has a content object that contains information about all the elements in the page; typically references to templates and associated data. Moya can then render this data structure with the template specified in the template attribute of <content>.

Lets look at the product-list.html template which renders the content:

<html>
    <head>
        <title>${title}</title>
    </head>
    <body>
        {% render sections.body %}
    </body>
</html>

This template inserts the title of the content (set by the <title> tag), and renders the body section from the content.

The <title> tag is actually a shortcut, equivalent to the following:

<str dst="title">Sushi Product Page</str>

This works because any data created in the content scope is passed to the template. Moya also passes a dictionary called sections to the template which contains the renderable elements defined in the sections.

When Moya sees {% render sections.body %} in the main template, it renders the body section, which contains three template nodes; one for each product. The template nodes render the following template (product.html):

<div class="product">
    <a href="{% url 'product' with product=product %}">Buy ${title:product}</a>
</div>

The end product will be a string contain HTML, which would look something like the following:

<html>
    <head>
        <title>Sushi Product Page</title>
    </head>
    <body>
        <div class="product">
            <a href="/sushifinder/product/nigiri/">Nigiri</a>
        </div>
        <div class="product">
            <a href="/sushifinder/product/tuna-roll/">Tuna-rooll</a>
        </div>
        <div class="product">
            <a href="/sushifinder/product/fugu/">Fugu</a>
        </div>
    </body>
</html>

In a real project, the content definition would have more sections and different types of renderable elements. But as requirements grow more complex, the code inside the <content> stays relatively manageable. Operations such as modifying template parameters, and moving markup from one content area to another are trivially simple, in contrast to a pure template approach.

NOTE The HTML code shown here is aligned for sake of readability, but may not match the actual rendered code (although the end result will be the same).

Rendering Content

The <render-content> tag is one way of rendering content. It renders content to a string, which you could then return from a view. Because you rarely want to do any more processing once you have a page of HTML, Moya also offers the <serve-content> tag which renders and serves content in one.

Here's how the previous example could be written to serve the content immediately:

<serve-content content="#content.product.list">
    <let products="['nigiri', tuna-roll', 'fugu']"/>
</serve-content>

You can also specify the content to render from the content attribute of the <view> tag. The following view renders content with the value for products created in the view scope:

<view libname="view.products" content="#content.product.list">
    <let products="['nigiri', tuna-roll', 'fugu']"/>
</view>

Serving views with content in this way follows the same logic regarding returned data as template views; the following is also valid:

<view libname="view.products" content="#content.product.list">
    <return-dict let:products="['nigiri', tuna-roll', 'fugu']" />
</view>

Nested Content

Content tags may contain other content tags. In fact, it is very common to have several levels of nested content in a typical page. Lets take the preceding example and demonstrate how to render nested content. We are going to move the products inside a template node which will wrap it with some HTML markup.

For sake of demonstration, we will wrap the list of products in an HTML <div> tag with a class of product-container. Here's the new content:

<moya>
    <content libname="content.product.list" template="product-list.html">
        <title>Sushi Product Page</title>
        <section name="body">
            <node template="product-container.html">
                <for src="products" dst="product">
                    <node template="product.html" let:product="product"/>
                </for>
            </node>
        </section>
    </content>
</moya>

The product nodes are now rendered inside another node with a template of product-container.html. This template has the additional responsibility of rendering its children as well. Rendering children can be done with the {% children %} template tag. Here is the product-container.html template:

<div class="product-container">
{% children %}
</div>

Now, when we render the content we will get the following:

<html>
    <head>
        <title>Sushi Product Page</title>
    </head>
    <body>
        <div class="product-container">
            <div class="product">
                <a href="/sushifinder/product/nigiri/">Nigiri</a>
            </div>
            <div class="product">
                <a href="/sushifinder/product/tuna-roll/">Tuna-rooll</a>
            </div>
            <div class="product">
                <a href="/sushifinder/product/fugu/">Fugu</a>
            </div>
        </div>
    </body>
</html>

Advanced Nesting

Occasionally it is useful to have more control over how sections are rendered. If a section is empty (or does not exist) it will evaluate to False. You can use this in a template to render a section only if it has content. For example, here's how we would modify product-list.html to only render the body section if it is non-empty:

<html>
    <head>
        <title>${title}</title>
    </head>
    <body>
        {%- if sections.body %}
        {% render sections.body %}
        {%- endif %}
    </body>
</html>

You may also iterate over the children in a content section and render them individually. You might want to do this if you want to wrap each child in markup. For example, lets take the product-container.html template and modify it so we wrap each product individually, rather than all of them:

<!-- product-container.html -->
{% for child in self %}
<div class="product-container">
    {% render child %}
</div>
{% endfor %}

The above template iterates over a value called self which is the current content object being rendered (in this case it is the <node> with template="product-container.html"). The {% render %} template tag renders each of the child nodes inside a <div>. This change would result in the following output:

<html>
    <head>
        <title>Sushi Product Page</title>
    </head>
    <body>
        <div class="product-container">
            <div class="product">
                <a href="/sushifinder/product/nigiri/">Nigiri</a>
            </div>
        </div>
        <div class="product-container">
            <div class="product">
                <a href="/sushifinder/product/tuna-roll/">Tuna-rooll</a>
            </div>
        </div>
        <div class="product-container">
            <div class="product">
                <a href="/sushifinder/product/fugu/">Fugu</a>
            </div>
        </div>
    </body>
</html>

Content HTML tags

Tags in a content definition are typically high-level; they specify what to render, and leave the how to a template. Occasionally though, it is useful to be able to specify the markup directly in the content. For instance, if you want to wrap content in a simple <div> and creating a another template seems overkill.

To insert simple HTML content you can use the http://moyaproject.com/html namespace. Any tag in that namespace will result in the equivalent tag in the rendered output. For example, lets take our list of sushi products and wrap them in a <div> with a class of products-column. Here's how we could do that:

<moya xmlns:html="http://moyaproject.com/html">
    <content libname="content.product.list" template="product-list.html">
        <title>Sushi Product Page</title>
        <section name="body">
            <html:div class="products-column">
                <node template="product-container.html">
                    <for src="products" dst="product">
                        <node template="product.html" let:product="product"/>
                    </for>
                </node>
            </html:div>
        </section>
    </content>
</moya>

Note the addition of xmlns:html="http://moyaproject.com/html" to the root tag which introduces the html namespace, and the html: prefix on the <html:div> tag. When this content is rendered, it will product the following output:

<html>
    <head>
        <title>Sushi Product Page</title>
    </head>
    <body>
        <div class="products-columm">
            <div class="product-container">
                <div class="product">
                    <a href="/sushifinder/product/nigiri/">Nigiri</a>
                </div>
            </div>
            <div class="product-container">
                <div class="product">
                    <a href="/sushifinder/product/tuna-roll/">Tuna-rooll</a>
                </div>
            </div>
            <div class="product-container">
                <div class="product">
                    <a href="/sushifinder/product/fugu/">Fugu</a>
                </div>
            </div>
        </div>
    </body>
</html>

Extending Content

A content definition may extend another, in much the same way as templates may be extended. When content is extended it inherits any data from the extended content, and sections with the same name are combined. The result may be rendered as normal.

Extending content is most often done when when there are common elements in a page and you don't want to repeat yourself. Lets write a content element for the sushi example that will display special offers on every page in the project. This content element will define a section named body with a single <node> that renders specials.html.

<moya>
    <content libname="content.base">
        <section name="body" merge="append">
            <node template="specials.html"/>
        </section>
    </content>
</moya>

To extend from this content, we need only add an extends attribute which contains an element reference to the base content. Here's how we would change the <content> tag to extend the base template, above:

<content libname="content.product.list" template="product-list.html" extends="#content.base">
    <!-- as previous content example -->
</content>

If we were to render the product list content now, the template specials.html will be inserted immediately prior to the three products. As will any content that extends from #content.base.

You may have noticed the merge attribute on the <section> in the base content. This tells Moya what do if a similarly-named section exists in both content definitions. This attribute may be set to one of the following three values:

replace
Replaces the content from the base section entirely (the default).
append
Appends new content to the similarly-named section being extended – which generally results in the markup appearing below the base content markup.
prepend
Prepends new content to the similarly-named section being extended.

Content may be extended multiple times, just be careful not to extend the same content definition multiple times in a chain, which would result in an error.

If the extends attribute is not specified, then Moya will extend from the content specified in the base_content setting in the [site] section of your project settings. This is a good way of customizing the look and feel on a per-site basis.

Widgets

A widget is a form of custom tag which generates content. At a simple level, a widget may take the place of a <node> in that it can render a template with data. Widgets may also run executable Moya code and pull in external files such as JS and CSS. This makes widgets very self-contained, in that you can move a widget tag from one page to another and the page will render correctly without any further changes to markup, stylesheets or Javascript.

Let's show how we could use custom widgets in place of node tags in the sushi examples. The following code defines a widget called <product>:

<widget name="product" template="widgets/product.html">
    <signature>
        <attribute name="product" type="expression" required="yes"/>
    </signature>
</widget>

This widget may now be used in place of the the equivalent <node>. The template attribute of <widget> defines the template to use. By convention, widget templates are placed in a subdirectory called widgets (within the library's template directory). The template itself is the same as the template used previously. Here it is again:

<!-- widgets/product.html -->
<div class="product">
    <a href="{% url 'product' with product=product %}">Buy ${title:product}</a>
</div>

And here is how you would use it in a content definition:

<moya xmlns:sushi="http://moyaproject.com/sushifinder">
    <content libname="content.product.list" template="product-list.html">
        <title>Sushi Product Page</title>
        <section name="body">
            <node template="product-container.html">
                <for src="products" dst="product">
                    <sushi:product product="product" />
                </for>
            </node>
        </section>
    </content>
</moya>

Note the addition of the namespace declaration in the first tag. The namespace URL should be the value used in the library's lib.ini file. The inner-most <node> has been replaced with the widget tag.

Adding CSS to a widget

Using a widget tag here has made the content definition marginally more readable, but we haven't gained much for this example. In a real-life example though, a widget will probably have at least some CSS associated with it. Let's add some CSS to the product widget. The following will create a CSS style that draws a red border around each prouduct:

<widget name="product" template="widgets/product.html">
    <signature>
        <attribute name="product" type="expression" required="yes"/>
    </signature>
    <css>
    .content
    {
    border: 1px solid red;
    }
    </css>
</widget>

When you render the content definition now, the product widget will add the CSS to the a section in the content called "css". To ensure that the css is added to our page, we need to render the css block in the base template. Here's how we would do that:

<html>
    <head>
        {% render sections.css unique %}
        <title>${title}</title>
    </head>
    <body>
        {% render sections.body %}
    </body>
</html>

Now when you render the content, the following code will be added inside the <head> markup:

<style type="text/css">
.content
{
border: 1px solid red;
}
</style>

Note the addition of the keyword unique in the template tag which renders the css section. This tells Moya not to render identical content more than once. This is so that if we have ten <product> tags on a page, we only get a single copy of the style tag.

While it is possible to write CSS in widgets like this, it is generally preferable to link to an external stylesheet, so that you can keep your code modular. To reference an external CSS files use the <include-css> tag, which takes the path to a CSS file in the path attribute. For example, we can save the following CSS as css/widgets/products.css in the library's media directory:

/* css/widgets/product.css */
.content
{
border: 1px solid red;
}

The widget definition would become:

<widget name="product" template="widgets/product.html">
    <signature>
        <attribute name="product" type="expression" required="yes"/>
    </signature>
    <include-css path="css/widgets/product.css" />
</widget>

The <include-css> tag adds a dictionary to the content called include which will contain a list of CSS paths called css. Here's how you can render the included CSS paths in the base template:

<html>
    <head>
        {% render include.css %}
        <title>${title}</title>
    </head>
    <body>
        {% render sections.body %}
    </body>
</html>

Moya won't add a CSS path to the list more than once, so the unique keyword is not required here.

Adding Javascript to a Widget

Associating javascript with a widget is very similar to adding CSS; the <js> tag adds Javascript to the js section, and <include-js> references a JS file in the library's media directory.

As with CSS, it is generally better to write external Javascript files and include them with <include-js>. An exception would be if the main functionality is in an external file but you also want a short snippet of code to initialize an individual widget. To demonstrate one way of doing this, we will look at some code from the Moya Comments library.

The comments widget renders the comments HTML and also invokes some JS. The widget includes the following line:

<include-js path="js/comments.js" />

This ensures that a script tag will be generated in the page to load comments.js, which contains a JQuery plugin:

Also in the widget is the following code:

<let id=".content.id" />
<js>
    $(function(){
        $('#${id}').moyaComments();
    });
</js>

The first line sets id to the value of .content.id which is updated every time a content tag adds some content – making it an effective unique ID for the current page. The <js> tag generates a short script that invokes the JQuery plugin for the comments widget being rendered.

The comments template starts with the following line:

<div class="moya-comments-container" id="${id}">

Note the reference to id, which is set to the same value that was used in the <js>. This connects the JQuery widget to the markup it applies to.

Common Sections

We've seen how adding a widget to a content definition requires that associated objects such as JS / CSS must be rendered in the base template. If we want to ensure that a widget renders equally well with different templates – even when added by third parties – we need to add a few common sections and render calls to our base templates.

Here's an example of a bear-bones HTML 5 base template with all common sections:

<!DOCTYPE html>
<html>
    <head>
        <!-- renders content in the "css" section -->
        {% block "css" %}{% render sections.css %}{% endblock %}
        <!-- renders CSS paths added with the <include-css> tag -->
        {% block "includecss" %}{% render include.css %}{% endblock %}
        <!-- include JS that must go in the head -->
        {% block "jshead" %}{% render sections.jshead %}{% endblock %}
        <!-- render other head content -->
        {% block "head" %}{% render sections.head %}{% endblock %}
        <!-- set the title -->
        <title>${title}</title>
    </head>
    <body>
        <!-- render main body section -->
        {% block "body" %}{% render sections.body %} {% endblock %}

        <!-- generate script tags to from JS paths included with <include-js> -->
        {% block "includejs" %}{% render include.js %}{% endif %}
        <!-- render Javascript sections -->
        {% block "js" %}{% render sections.js unique%}{% endblock %}
        <!-- JS that must go at the bottom of the page -->
        {% block "jsfoot" %}{% render sections.jsfoot unique%}{% endblock %}
    </body>
</html>

The common sections as as follows:

"css"

This block renders content from the "css" section, such as html <style> tags added by the <css> tag. It is the head of the HTML.

"includecss"

This block renders the list of CSS paths added by the <include-css> tag.

"jshead"

This block adds Javascript code that must be in the head of the HTML document. Note, that the <js> tag adds to the "js" section by default. If you want to add to the "jshead" section, specify it with the section attribute. For example:

<js section="jshead">
    alert("Ready for take-off!");
</js>

This would produce the following output in the "jshead" block:

<script type="text/javascript">
    alert("Ready for take-off!");
</script>

Which would create an annoying popup when your page loads.

"head"

This block should contain any other markup that should appear in the head of the HTML.

"body"

This block renders the body section which contains the main visible content. This is often overridden to create several content areas. For example, you could use the following template to divide the body in to separate content areas:

<!-- column-base.html -->
{% extends "base.html" %}

{% block "body" %}
<div class="container">
    <div class="content">
        {% render sections.content %}
    </div>
    <div class="column">
        {% render sections.column %}
    </div>
</div>
<div class="footer">
    {% render sections.footer %}
</div>
{% endblock %}

Because the above template extends the base, it inherits the base template's blocks. It also adds three new sections that will render content. You can choose what content goes where in the content definition. Here's an example:

<content libname="content.article" template="column-base.html">
    <section name="content">
        <sushi:article article="article" />
    </section>
    <section name="column">
        <sushi:recent-articles />
    </section>
    <section name="footer">
        <text>Copyright 2014 Sushifinder PLC<text>
    </section>
</content>

"includejs"

This block renders the list of JS paths added by the <include-js> tag. It is generally best to place this block at the end of the page, because it can delay page render time if the browser has to wait for external Javascript to load before it can render the page content.

"js"

This block renders JS added to the content with the <js> tag. It is generally placed at the end of the page to speed up page render times – but could equally be in the head of the page.

"jsfoot"

This block renders JS that should be included at the end of the page.