Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

Templates for Web Pages

Save for later
  • 13 min read
  • 13 Oct 2015

article-image

In this article, by Kai Nacke, author of the book D Web Development, we will learn that every website has some recurring elements, often called a theme. Templates are an easy way to define these elements only once and then reuse them. A template engine is included in vibe.dwith the so-called Diet templates. The template syntax is based on the Jade templates (http://jade-lang.com/), which you might already know about.

In this article, you will learn the following:

  • Why are templates useful
  • Key concepts of Diet templates: inheritance, include and blocks
  • How to use filters and how to create your own filter

(For more resources related to this topic, see here.)

Using templates

Let's take a look at the simple HTML5 page with a header, footer, navigation bar and some content in the following:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Demo site</title>
    <link rel="stylesheet" type="text/css" href="demo.css" />
  </head>
  <body>
    <header>
      Header
    </header>
    <nav>
      <ul>
        <li><a href="link1">Link 1</a></li>
        <li><a href="link2">Link 2</a></li>
        <li><a href="link3">Link 3</a></li>
      </ul>
    </nav>
    <article>
      <h1>Title</h1>
      <p>Some content here.</p>
    </article>
    <footer>
      Footer
    </footer>
  </body>
</html>

The formatting is done with a CSS file, as shown in the following:

body {
  font-size: 1em;
  color: black;
  background-color: white;
  font-family: Arial;
}
header {
  display: block;
  font-size: 200%;
  font-weight: bolder;
  text-align: center;
}
footer {
  clear: both;
  display: block;
  text-align: center;
}
nav {
  display: block;
  float: left;
  width: 25%;
}
article {
  display: block;
  float: left;
}

Despite being simple, this page has elements that you often find on websites. If you create a website with more than one page, then you will use this structure on every page in order to provide a consistent user interface. From the 2nd page, you will violate the Don't Repeat Yourself(DRY) principle: the header and footer are the elements with fixed content. The content of the navigation bar is also fixed but not every item is always displayed. Only the real content of the page (in the article block) changes with every page.

Templates solve this problem. A common approach is to define a base template with the structure. For each page, you will define a template that inherits from the base template and adds the new content.

Creating your first template

In the following sections, you will create a Diet template from the HTML page using different techniques.

Turning the HTML page into a Diet template

Let's start with a one-to-one translation of the HTML page into a Diet template. The syntax is based on the Jade templates. It looks similar to the following:

doctype html
html
  head
    meta(charset='utf-8')
    title Demo site
    link(rel='stylesheet', type='text/css', href='demo.css')
  body
    header
      | Header
    nav
      ul
        li
          a(href='link1') Link 1
        li
          a(href='link2') Link 2
        li
          a(href='link3') Link 3
    article
      h1 Title
      p Some content here.
    footer
      | Footer

The template resembles the HTML page. Here are the basic syntax rules for a template:

  • The first word on a line is an HTML tag
  • Attributes of an HTML tag are written as a comma-separated list surrounded by parenthesis
  • A tag may be followed by plain text that may contain the HTML code
  • Plain text on a new line starts with the pipe symbol
  • Nesting of elements is done by increasing the indentation.

If you want to see the result of this template, save the code as index.dt and put it together with the demo.css CSS file in the views folder.

The Jade templates have a special syntax for the nested elements. The list item/anchor pair from the preceding code could be written in one line, as follows:

li: a(href='link1') Link1

This syntax is currently not supported by vibe.d.

Now, you need to create a small application to see the result of the template by following the given steps:

  • Create a new project template with dub, using the following command:
    $ dub init template vibe.d
  • Save the template as the views/index.dt file.
  • Copy the demo.css CSS file in the public folder.
  • Change the generated source/app.d application to the following:
    import vibe.d;
    
    shared static this()
    {
        auto router = new URLRouter;
        router.get("/", staticTemplate!"index.dt");
        router.get("*", serveStaticFiles("public/"));
    
        auto settings = new HTTPServerSettings;
        settings.port = 8080;
        settings.bindAddresses = ["::1", "127.0.0.1"];
        listenHTTP(settings, router);
    
        logInfo("Please open http://127.0.0.1:8080/ in your browser.");
    }

Run dub inside the project folder to start the application and then browse to http://127.0.0.1:8080/ to see the resulting page.

The application uses a new URLRouter class. This class is used to map a URL to a web page. With the router.get("/", staticTemplate!"index.dt");statement, every request for the base URL is responded with rendering of the index.dt template. The router.get("*", serveStaticFiles("public/")); statement uses a wild card to serve all other requests as static files that are stored in the public folder.

Adding inheritance

Up to now, the template is only a one-to-one translation of the HTML page. The next step is to split the file into two, layout.dt and index.dt. The layout.dtfile defines the general structure of a page while index.dt inherits from this file and adds new content.

The key to template inheritance is the definition of a block. A block has a name and contains some template code. A child template may replace the block, append, or prepend the content to a block. In the following layout.dt file, four blocks are defined: header, navigation, content and footer. For all the blocks, except content, a default text is defined, as follows:

doctype html
html
    head
        meta(charset='utf-8')
        title Demo site
        link(rel='stylesheet', type='text/css', href='demo.css')
    body
        block header
            header Header
        block navigation
            nav
                ul
                    li <a href="link1">Link 1</a>
                    li <a href="link2">Link 2</a>
                    li <a href="link3">Link 3</a>
        block content
        block footer
            footer Footer

The template in the index.dt file inherits this layout and replaces the block content, as shown here:

extends layout
block content
    article
        h1 Title
        p Some content here.

You can put both the files into the views folder and run dub again. The rendered page in your browser still looks the same.

You can now add more pages and reuse the layout. It is also possible to change the common elements that you defined in the header, footer and navigation blocks.

There is no restriction on the level of inheritance. This allows you to construct very sophisticated template systems.

Using include

Inheritance is not the only way to avoid repetition of template code. With the include keyword, you insert the content of another file. This allows you to put the reusable template code in separate files. As an example, just put the following navigation in a separate navigation.dtfile:

nav
    ul
        li <a href="link1">Link 1</a>
        li <a href="link2">Link 2</a>
        li <a href="link3">Link 3</a>

The index.dt file uses the include keyword to insert the navigation.dt file, as follows:

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at ₹800/month. Cancel anytime
doctype html
html
    head
       meta(charset='utf-8')
        title Demo site
        link(rel='stylesheet', type='text/css', href='demo.css')
    body
        header Header
        include navigation
        article
            h1 Title

            p Some content here.

        footer Footer

Just as with the inheritance example, you can put both the files into the views folder and run dub again. The rendered page in your browser still looks the same.

The Jade templates allow you to apply a filter to the included content. This is not yet implemented.

Integrating other languages with blocks and filters

So far, the templates only used the HTML content. However, a web application usually builds on a bunch of languages, most often integrated in a single document, as follows:

  • CSS styles inside the style element
  • JavaScript code inside the script element
  • Content in a simplified markup language such as Markdown

Diet templates have two mechanisms that are used for integration of other languages.

If a tag is followed by a dot, then the block is treated as plain text. For example, the following template code:

p.
    Some text
    And some more text

It translates into the following:

<p>
    Some text
    And some more text
</p>

The same can also be used for scripts and styles. For example, you can use the following script tag with the JavaScript code in it:

script(type='text/javascript').

    console.log('D is awesome')

It translates to the following:

<script type="text/javascript">
    console.log('D is awesome')
</script>

An alternative is to use a filter. You specify a filter with a colon that is followed by the filter name. The script example can be written with a filter, as shown in the following:

:javascript

    console.log('D is awesome')

This is translated to the following:

<script type="text/javascript">

    //<![CDATA[

    console.log('D is aewsome')

    //]]>

</script>

The following filters are provided by vibe.d:

  • javascript for JavaScript code
  • css for CSS styles
  • markdown for content written in Markdown syntax
  • htmlescapeto escape HTML symbols

The css filter works in the same way as the javascript filter.

The markdown filter accepts the text written in the Markdown syntax and translates it into HTML. Markdown is a simplified markup language for web authors. The syntax is available on the internet at http://daringfireball.net/projects/markdown/syntax. Here is our template, this time using the markdown filter for the navigation and the article content:

doctype html
html
    head
        meta(charset='utf-8')
        title Demo site
        link(rel='stylesheet', type='text/css', href='demo.css')
    body
       header Header
        nav
            :markdown
                - [Link 1](link1)

                - [Link 2](link2)

                - [Link 3](link3)
        article
            :markdown
                Title
                =====
                Some content here.
        footer Footer

The rendered HTML page is still the same. The advantage is that you have less to type, which is good if you produce a lot of content. The disadvantage is that you have to remember yet another syntax.

A normal plain text block can contain HTML tags, as follows:

p.
    Click this <a href="link">link</a>

This is rendered as the following:

<p>
    Click this <a href="link">link</a>
</p>

There are situations where you want to even treat the HTML tags as plain text, for example, if you want to explain HTML syntax. In this case, you use the htmlescape filter, as follows:

p
    :htlmescape
        Link syntax: <a href="url target">text to display</a>

This is rendered as the following:

<p>
    Link syntax: &lt;a href="url target"&gt;text to display&lt;/a&gt;
</p>

You can also add your owns filters. The registerDietTextFilter()function is provided by vibe.d to register the new filters. This function takes the name of the filter and a pointer to the filter function. The filter function is called with the text to filter and the indentation level. It returns the filtered text. For example, you can use this functionality for pretty printing of D code, as follows:

  1. Create a new project with dub,using the following command:
    $ dub init filter vibe.d
  2. Create the index.dttemplate file in the viewsfolder. Use the new dcodefilter to format the D code, as shown in the following:
    doctype html
    head
        title Code filter example
        :css
            .keyword { color: #0000ff;
                       font-weight: bold; }
    body
        p You can create your own functions.
        :dcode
            T max(T)(T a, T b) {
                if (a > b) return a;
                return b;
            }
  3. Implement the filter function in the app.dfile in the sourcefolder. The filter function outputs the text inside a <pre> tag. Identified keywords are put inside the <span class="keyword"> element to allow custom formatting. The whole application is as follows:
    import vibe.d;
    
    string filterDCode(string text, size_t indent)
    {
      import std.regex;
      import std.array;
    
      auto dst = appender!string;
      filterHTMLEscape(dst, text, HTMLEscapeFlags.escapeQuotes);
      auto regex = regex(r"(^|s)(if|return)(;|s)");
      text = replaceAll(dst.data, regex, "$1<span class="keyword">$2</span>$3");
      auto lines = splitLines(text);
    
      string indent_string = "n";
      while (indent-- > 0) indent_string ~= "t";
    
      string ret = indent_string ~ "<pre>";
      foreach (ln; lines) ret ~= indent_string ~ ln;
      ret ~= indent_string ~ "</pre>";
    
      return ret;
    }
    
    shared static this()
    {
      registerDietTextFilter("dcode", &filterDCode);
    
      auto settings = new HTTPServerSettings;
      settings.port = 8080;
      settings.bindAddresses = ["::1", "127.0.0.1"];
      listenHTTP(settings, staticTemplate!"index.dt");
    
      logInfo("Please open http://127.0.0.1:8080/ in your browser.");
    }

Compile and run this application to see that the keywords are bold and blue.

Summary

In this article, we have seen how to create a Diet template using different techniques such as translating the HTML page into a Diet template, adding inheritance, using include, and integrating other languages with blocks and filters.

Resources for Article:


Further resources on this subject: