Template documents represent a middle ground between documents that can contain some data in front matter and Origami files that contain templates.
- A template document file is identified with two extensions, where the second-to-last extension is
.ori
, likeindex.ori.html
orabout.ori.md
. - When you ask Origami to evaluate such a file, it will implicitly inline the results of any Origami expressions inside the file.
A template document is appropriate when you have a long template that may need portions of embedded or attached code. (For brevity, some of the samples shown below have very short templates.)
There are three different kinds of template documents:
- Text with embedded substitutions
- Body text with YAML front matter
- Body text with Origami front matter
These largely work the same, but with some differences described below.
Text with embedded substitutions
This template document is called inline.ori.html
:
<!DOCTYPE html>
<html>
<head>
<style>
${ inline.css }
</style>
</head>
<body>
This text will be red.
</body>
</html>
Substitutions inside a template document are full Origami expressions so, among other things, they can reference other documents. The above template includes an embedded Origami expression that references a separate file, inline.css
.
/* inline.css */
body { color: red }
The result of the inline.ori.html
template is a function that returns a string. (The function can accept a single parameter; see below.)
If you have ask Origami to evaluate the template, it will call that function and return the resulting text. The text will contain the results of all the expressions in the document.
In this example, evaluating the function inlines the referenced CSS file:
$ ori inline.ori.html/
<!DOCTYPE html>
<html>
<head>
<style>
body { color: red }
</style>
</head>
<body>
This text will be red.
</body>
</html>
Accepting an argument
By default, a template document like this can be called as a function with one argument referenced with a _
underscore.
<!-- bold.ori.html -->
<b>${ _ }</b>
When called as a function, any value passed to this template will be incorporated into the output:
$ ori "bold.ori.html('Hooray')"
<b>Hooray</b>
Such templates behave like simple components. You can use them decompose the construction of complex documents into smaller pieces that are easier to understand.
Body text with YAML front matter
Like other text documents, a template document can include YAML front matter at the top of the document, enclosed in lines of ---
three hyphens.
Suppose shopping.ori.html
contains:
---
list:
- Loaf of Bread
- Container of Milk
- Stick of Butter
---
Things to buy:
<ul>
${ map(list, (item) => indent`
<li>${ item }</li>
`) }
</ul>
The front matter is treated as YAML. This can be used to define additional data — here, a list.
The front matter data is available to expressions in the body text, so the expression in the body text can reference the list
:
$ ori shopping.ori.html/
list:
- Loaf of Bread
- Container of Milk
- Stick of Butter
"@text": |
Things to buy:
<ul>
<li>Loaf of Bread</li>
<li>Container of Milk</li>
<li>Stick of Butter</li>
</ul>
The result of the template is a plain object containing all of the front matter data, plus a @text
property with the result of evaluating the body text.
Body text with Origami front matter
Alternatively, front matter can be an Origami expression that returns a function, function call, object literal, etc.
Defining the value of the template document
If Origami front matter is present, that will be evaluated and returned as the result of invoking the template document. Within this front matter, you can invoke the template’s body text as @template
.
Example: a website defines its “About” page as a template document called about.ori.html
:
---
page.ori.html(@template())
---
<article>
<p>We have fun making websites.</p>
</article>
The front matter of this document is an Origami expression that will be evaluated and returned as the result of the template document.
In this case, the expression invokes the template’s body text via @template
, then passes that to a base page.ori.html
template defined separately:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
</head>
<body>
${ _ }
</body>
</html>
When you ask for the value of about.ori.html
, that in turn calls page.ori.html
:
$ ori about.ori.html/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
</head>
<body>
<article>
<p>We have fun making websites.</p>
</article>
</body>
</html>
Returning an object
Sometimes a template is primarily body text but the result should include some calculated data.
This can be achieved using the above principle of placing an Origami expression in the front matter. In this case, the front matter can define an object using an object literal.
If calcs.ori.md
contains:
---
{
sum: 1 + 1
@text: @template()
}
---
One plus one is ${ sum }.
then invoking this returns an object:
$ ori calcs.ori.md/
sum: 2
"@text": |
One plus one is 2.
Returning a function
To define your template document as a more complex function — e.g., one that accepts multiple arguments, or that calls other functions — define a function in the front matter.
This link.ori.html
template accepts href
and text
parameters to return an HTML link:
---
(href, text) => @template()
---
<a href="${ href }">${ text }</a>
The value of the href
and link
parameters are in scope for expressions in the template body.
$ ori "link.ori.html('https://weborigami.org', 'Web Origami')"
<a href="https://weborigami.org">Web Origami</a>
Behavior within a map
When used inside a tree:map
function, a template document will provide a default key
function to the map. This key
function will add the template document’s last extension to keys in the map’s output.
For example, this template is called movie.ori.html
, so it will add .html
to keys in a map.
<!-- movie.ori.html -->
<article>
<h1>${ _/title } (${ _/year })</h1>
</article>
When applied to this data:
# movies.yaml
kiki:
title: Kiki's Delivery Service
year: 1989
mononoke:
title: Princess Mononoke
year: 1997
spirited:
title: Spirited Away
year: 2001
heron:
title: The Boy and the Heron
year: 2023
the values will end up with .html
extensions:
$ ori map movies.yaml, movie.ori.html
kiki.html: |
<article>
<h1>Kiki's Delivery Service (1989)</h1>
</article>
mononoke.html: |
<article>
<h1>Princess Mononoke (1997)</h1>
</article>
spirited.html: |
<article>
<h1>Spirited Away (2001)</h1>
</article>
heron.html: |
<article>
<h1>The Boy and the Heron (2023)</h1>
</article>
You can override this behavior by explicitly providing a key
option to tree:map
.