Creating your first page

This is a tad misleading. Instead of creating a brand new page, we're going to modify the existing home page and cover a couple of things about Selmer along the way. But first, we need to determine where the HTML is for the home page.

Recall that our hipstr.handler/app uses three Ring handlers: home-routes, base-routes, and test-routes. We know that test-routes doesn't handle the home page because we just created it, and we can see that base-routes is defined in hipstr.handler and is responsible for handling "HTTP 404: Page Not Found" responses and requests to our static resources. This leaves the home-routes, which in hindsight, is pretty obvious given the name.

The home-routes handler is defined in the hipstr.routes.home namespace (/src/hipstr/routes/home.clj). The namespace defines two routes and two functions responsible for rendering each respective route's response. Notably, we see the following code right near the bottom:

(GET "/" [] (home-page))

This route serves hipstr's root page, whose content is generated by the home-page function.

Rendering a page

The home-page function isn't doing much. In fact, all it does is call hipstr.layout/render, and provide the template name and a context map of values:

(defn home-page []
  (layout/render
  "home.html" {:content (util/md->html "/md/docs.md")}))

Note

The preceding code shines a golden nugget about Luminus: it supports rendering Markdown out of the box. This book will not get into Markdown, however, you can read about its splendid syntax at http://daringfireball.net/projects/markdown/syntax.

The home.html template in /resources/templates/home.html is where the visual meat of this route lives. Ultimately, it's just an HTML file with some Selmer markup. Let's discuss a few basic things about Selmer markup before we start tearing away at the template, specifically variables, tags, and filters.

Variables

A templating system wouldn't be very useful if it didn't have the notion of variables. If we didn't have variables, then we'd never be able to get dynamic data into our template and then all the puppies in the world would suddenly be very, very sad.

Variables in Selmer are denoted using double curly braces, such as {{variable-name}}. The value of the variable is determined by a matching key in the context map passed to the template via the layout/render function. In the home-route function, explained previously, we passed a context map with a single key:

{:content (util/md->html "/md/docs.md")}

That key is now available as a Selmer variable called content, and we can render its HTML escaped value to the browser by sticking it between two curlies:

{{content}}

This is exactly what is happening in the /resources/templates/home.html file:

<div class="row-fluid">
  <div class="span8">
    {{content|safe}}
  </div>
</div>

Assuming a context map of {:content "Hello World!"}, the preceding fragment would actually be rendered as this:

<div class="row-fluid">
  <div class="span8">
    Hello World!
  </div>
</div>

Note

What's up with that |safe bit? We'll get to that in a bit. For now, just assume that it means you are blindly trusting that the content is nothing malicious.

Variables don't have to be flat, however, they can also be structured. For example, pretend we had the following context map:

{:person {:first-name "Ryan"
              :last-name "Baldwin"
              :favourite-animal "Elephant"}}

This would resolve to a structured Selmer variable that we could dig into using dot-notation.

<div class="row-fluid">
  <div class="span8">
    Hello {{person.first-name}} {{person.last-name}}!
    I see your favourite animal is the
    {{person.favourite-animal}}. How exciting!
  </div>
</div>

However, what happens if we try and pull the value of a variable that's not defined in the context map? For example, what if we changed the preceding code to read:

I see you prefer your {{person.favourite-animal}} to be {{person.favorite-color}}. How odd.

Since our context map did not define a favorite-color key, {{person.favorite-color}} will simply resolve to an empty string.

Filters

Filters are basically functions that operate over a variable's value. In our previous discussion about variables, we saw the following code:

{{content|safe}}

Here, we apply the safe filter to the value of content or, put another way, we are passing the value of content into the function that sits behind the safe filter. The result of the filter is what's subsequently rendered. In our example, safe restricts HTML escaping the value of content. So, if the value of content was something like <h1>Hello World!</h1>, applying the safe filter would render that value into the DOM verbatim, instead of HTML escaping it to &lt;h1&gt;Hello World!&lt;/h1&gt;.

Filter parameters

Some filters require arguments above and beyond the value we're applying the filter to, such as the default filter. The default filter allows us to define a default value to use—other than an empty string—if the variable's value has not been set. As such, we need to provide the default filter with what we want that value to be. We do this using a colon:

{{content|default:"This is some default crud."}}

This will render the value of content, or if content is not set, render This is some default crud.

Note

You can read a complete list of Selmer's built-in filters at https://github.com/yogthos/Selmer#built-in-filters-1.

Tags

Whereas variables live inside {{ }}, tags live inside {% %}. Selmer tags are something like commands or instructions. Some of them are a simple one line statement called inline tags, such as include. Others contain a content body (which I'll refer to as content tags, for the purpose of avoiding ambiguity), such as if and block. All of them, however, contain some kind of expression with varying complexity, respective to the tag.

For example, the include tag's expression is the absolute path to the file we want to include at that location in the page:

{% include "templates/some-other-template.html" %}

Comparatively, the if tag requires an expression of truthiness and a content block:

{% if 5 > 4 %}
  <h2>Newsflash!</h2>
  <p>Five is always bigger than 4.</p>
{% endif %}

In this scenario, the content block (HTML fragment) will only be rendered if the expression in the if tag evaluates to true (which it always is in our case).

Note

Selmer has just over a dozen different tags available at your disposal, which you can read at https://github.com/yogthos/Selmer#built-in-tags-1.

Template inheritance

Like many templating libraries, Selmer allows a form of template inheritance. Templates can extend other templates through the use of block tags, which define a content body that can be overwritten by child templates. If we open the base.html template (/resources/templates/base.html), we see the following snippet near the middle of page:

<div class="container">
  {% block content %}
  {% endblock %}
</div>

Here, we've defined a block called content, but without any copy. The idea being that any template that inherits this template can populate this block's copy by defining block with the same name in the child. For example, say we had the following lines of code:

<!-- parent.html -->
<div class="example">
{% block example-content %}
{% endblock %}
</div>
<!-- child.html -->
{% extends "parent.html" %}
{% block example-content %}
Press the button to get the party started. <button>Start Party</button>
{% endblock %}

If we were to render child.html, the actual output would be:

<div class="example">
Press the button to get the party started <button>Start Party</button>
</div>

However, if we were to render parent.html, the content would be empty:

<div class="example">
</div>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.234.150