THT is in early Beta. We welcome contributors & feedback.

THT Templates

THT introduces template functions, which let you embed HTML and other content within your scripts.

Overview 

Templates look and act just like functions, but use the template keyword.

The type of template (e.g. 'html') is indicated in the name of the template.

Instead of code, the body of a template is a freeform multiline string.

When it called, the body is transformed according to its type and then returned as a LockString, which can then be passed to your output.

Whitespace and extra indentation is trimmed so you can indent however you wish.

Web.sendPage({
    title: 'My Website',
    body: pageHtml()
});

// An HTML template
template pageHtml() {

    <h1>My Website</h1>
    <p>Welcome to my site!</p>

}

TipBecause templates are just functions, they can be be organized any way you like: by page, modules, classes, etc.

Sandboxing 

Calls to the Db, File, and System modules are not allowed within templates.

This keeps your front-end (“view”) code separate from your back-end code, making your app easier to maintain over time.

Performance 

Template functions are compiled to PHP as pure string concatenation functions, so they usually execute very quickly.

HTML templates are parsed at compile time and cached.

Template Logic 

There are two ways to include THT logic in a template.

Expressions {{ ... }}

THT expressions can be embedded with double-curly braces.

The result is automatically escaped according to the type of template.

template pageHtml(userName) {

    <h1>My Website</h1>
    <p>Hello, {{ userName.upperCase() }}!</p>

}

Pepper Lines ::

Lines starting with the Pepper operator :: will be evaluated as inline THT.

Pepper lines must end in a semicolon or curly brace. If you need a larger block of logic, you should probably put it in a separate function.

template userListHtml(users) {

    :: let numUsers = users.length();

    :: if (!numUsers) {
        <p>No users here!</p>
    :: } else {
        <p>There are {{ numUsers }} users:</p>
        <ul>
        :: for (user in users) {
            <li>{{ user }}</li>
        :: }
        </ul>
    :: }
}

Nested Templates 

The output of other templates are included as-is (without escaping) if the template types are the same.

In this way, you can use smaller templates as “partials”.

// a single post link
template postLinkHtml(post) {

    <a href={{ post.url }}>{{ post.title }}</a>

}

// a list of post links
template allPostsHtml(posts) {

    <h1>Posts</h1>
    <ul>
    :: for (p in posts) {
        <li>{{ postLinkHtml(p) }}</li>
    :: }
    </ul>

}

Template Types 

The name of your template must end in a suffix that tells THT how it should process the content.

Supported types are:

HTML Templates 

See THTML shortcuts for quicker ways to write HTML in your templates.

Extra whitespace inside of multiline tags is automatically trimmed so you can indent your tags without affecting the output with stray spaces.

// An HTML template
template pageHtml() {

    <h1>My Website</h1>
    <p>Welcome to my site!</p>

}

Format Rules

CSS Templates 

THT expressions within CSS should only be used as property values.

Characters like ; and { } will be removed.

template siteCss(brandColor) {

    header {
        background-color: {{ brandColor }};
    }

}

When a CSS LockString is included in an HTML template, it will wrap the content in a <style> block.

See the Css module for stylesheet helpers.

JavaScript (Js) Templates 

THT expressions within a Js template are converted to JavaScript data values.

It handles Strings, Flags, Numbers. Maps & Lists are converted to JSON.

When a Js LockString is included in an HTML template, it will wrap the content in a <script> block and a self-executing function.

// In THT...
mainJs('Bob Johnson');

template mainJs(userName) {

    var userName = {{ userName }};

}

// When included in an HTML template, it looks like this:
<script>
(function(){
    var userName = "Bob Johnson";
})();
</script>

JCON Templates 

JCON is a nested data format that is easier to create and edit by hand, than constructing a literal Map.

Jcon templates return a Map or List instead of a LockString.

THT expressions or logic are not supported.

let data = dataJcon();
print(data.myKey[1]);  //= 'list item 1'

template dataJcon() {
    {
        myKey: [
            list item 0
            list item 1
        ]

        myOtherKey: true
    }
}

Litemark (Lite) Templates 

Litemark is a lightweight markup language for writing content, documentation, blog articles, forum posts, etc.

NoteTHT expressions aren’t well supported in Litemark templates yet.

template mainLite() {

    # Heading

    Lorem ipsum thtum.

    - List Item 1
    - List Item 2
}

Text Templates 

Text templates do not transform or escape the content.

They return a plain string instead of a LockString.

template emailText(name) {

     Hello {{ name }},

     Thanks for joining my website!

     -- Webmaster
}