oddmu-templates(5)
Name
oddmu-templates - how to write the templates
Synopsis
Some HTML files act as templates. They contain special placeholders in double bracers {{like this}}.
Description
Each template receives an object and uses the object's properties to replace the placeholders.
- *add.html* uses a *page*
- *diff.html* uses a *page*
- *edit.html* uses a *page*
- *feed.html* uses a *feed*
- *list.html* uses a *list*
- *preview.html* uses a *page*
- *search.html* uses a *search*
- *static.html* uses a *page*
- *upload.html* uses an *upload*
- *view.html* uses a *page*
Page
A page has the following properties:
- {{.Title}}* is the page title. If the page doesn't provide its own title, the page name is used.
- {{.Name}}* is the page name, escaped for use in URLs. More specifically, it is percent-escaped except for the slashes. The page name doesn't include the *.md* extension.
- {{.Dir}}* is the page directory, percent-escaped except for the slashes.
- {{.Base}}* is the basename of the current file (without the directory and without the *.md* extension), escaped for use in URLs.
- {{.Language}}* is the suspected language of the page. This is used to set the language on the *view.html* template. See "Non-English hyphenation" below.
- {{.Body}}* is the raw byte content of the page. Use *{{printf "%s" .Body}}* to get the Markdown, as a string. This is used for the text area of the *edit.html* template.
- {{.Hashtags}}* is an array of strings.
- {{.Html}}* contains some sort of HTML that depends on the template used.
- For *view.html*, it is the rendered Markdown, as HTML.
- For *search.html*, it is a page summary, with bold matches, as HTML.
- For *feed.html*, it is the escaped (!) HTML of the feed item.
- {{.IsBlog}}* says whether the current page has a name starting with an ISO date.
- {{.Today}}* is the current date, in ISO format. This is useful for "new page" like links or forms (see **EXAMPLE** below).
- {{.Parents}}* is the array of links to parent pages (see **EXAMPLE** below). To refer to them, you need to use a *{{range .Parents}}* … *{{end}}* construct. A link has to properties, *{{.Title}}* and *{{.Url}}*.
- {{.Diff}}* is the page diff for *diff.html*. It is only computed on demand so it can be used in other templates, too. It probably doesn't make much sense to do so, however.
Feed
The feed contains an item for the head of the feed and an array of items.
- {{.Items}}* is the array of feed items. To refer to them, you need to use a *{{range .Items}}* … *{{end}}* construct.
If page A links to pages B and C, the head of the feed is based on page A and the list of items contains B and C.
An item is a page plus a date. All the properties of a page can be used (see **Page** above).
- {{.Date}}* is the date of the last update to the page, in RFC 822 format.
List
The list contains a directory name and an array of files.
- {{.Dir}}* is the directory name that is being listed.
- {{.Files}}* is the array of files. To refer to them, you need to use a *{{range .Files}}* … *{{end}}* construct.
Each file has the following attributes:
- {{.Name}}* is the filename. The ".md" suffix for Markdown files is part of the name (unlike page names).
- {{.Title}}* is the page title, if the file in question is a Markdown file.
- {{.IsDir}}* is a boolean used to indicate that this file is a directory.
- {{.IsUp}}* is a boolean used to indicate the entry for the parent directory (the first file in the array, unless the directory being listed is the top directory). The filename of this file is "..".
- {{.Date}}* is the last modification date of the file.
Search
- {{.Query}}* is the query string.
- {{.Dir}}* is the directory in which the search starts, percent-escaped except for the slashes.
- {{.Previous}}*, *{{.Page}}* and *{{.Next}}* are the previous, current and next page number in the results since doing arithmetics in templates is hard. The first page number is 1. The last page is expensive to dermine and so that is not available.
- {{.More}}* indicates if there are any more search results.
- {{.Results}}* indicates if there were any search results at all.
- {{.Items}}* is an array of results. To refer to them, you need to use a *{{range .Items}}* … *{{end}}* construct.
A result is a page plus a score and possibly images. All the properties of a page can be used (see **Page** above).
- {{.Score}}* is a numerical score. It is only computed for *search.html*.
- {{.Images}}* are the images where the alt-text matches at least one of the query terms (but not predicates and not hashtags since those apply to the page as a whole). To refer to them, you need to use a *{{range .Images}}* … *{{end}}* construct.
Each image has three properties:
- {{.Title}}* is the alt-text of the image. It can never be empty because images are only listed if a search term matches.
- {{.Name}}* is the file name for use in URLs.
- {{.Html}}* the image alt-text with a bold tag used to highlight the first search term that matched.
Upload
- {{.Dir}}* is the directory where the uploaded file ends up, based on the URL path, percent-escaped except for the slashes.
- {{.Name}}* is the *filename* query parameter.
- {{.Last}}* is the filename of the last file uploaded.
- {{.Actual}}* is an array of filenames of all the files uploaded. Use {{range .Actual}} … {{.}} … {{end}} to loop over all the filenames.
- {{.Base}}* is the basename of the first file uploaded (without the directory, extension and numeric part at the end), escaped for use in URLs.
- {{.Title}}* is the title of the basename, if it exists.
- {{.Image}}* is a boolean to indicate whether the last file uploaded has a file name indicating an image or not (such as ending in *.jpg*). If so, a thumbnail can be shown by the template, for example.
- {{.MaxWidth}}* is the *maxwidth* query parameter, i.e. the value used for the previous image uploaded.
- {{.Quality}}* is the *quality* query parameter, i.e. the value used for the previous image uploaded.
- {{.Today}}* is the current date, in ISO format.
Non-English hyphenation
Automatic hyphenation by the browser requires two things: The style sheet must indicate "hyphen: auto" for an HTML element such as "body", and that element must have a "lang" set (usually a two letter language code such as "de" for German).
Oddmu attempts to detect the correct language for each page. It assumes that languages are not mixed on the same page. If you know that you're only going to use a small number of languages – or just a single language! – you can set the environment variable ODDMU_LANGUAGES to a comma-separated list of ISO 639-1 codes, e.g. "en" or "en,de,fr,pt".
"view.html" is used the template to render a single page and so the language detected is added to the "html" element.
"search.html" is the template used to render search results and so "en" is used for the "html" element and the language detected for every page in the search result is added to the "article" element for each snippet.
"edit.html" and "add.html" are the templates used to edit a page and at that point, the language isn't known, so "en" is used for the "html" element and no language is used for the "textarea" element.
Examples
The following link in a template takes people to today's page. If no such page exists, they are redirected to the edit form where it can be created.
<a href="/view/{{.Today}}" accesskey="t">Today</a>
The following form allows people to edit the suggested page name.
<form role="new" action="/edit/{{.Dir}}" method="GET">
<label for="id">New page:</label>
<input id="id" type="text" spellcheck="false" name="id"
accesskey="g" value="{{.Today}}" required>
<button>Edit</button>
</form>
The following puts the current date into the text area if and only if the page itself is a blog page. Useful for *add.html*:
<textarea name="body" rows="20" cols="80" placeholder="Text" lang=""
autofocus required>{{- if .IsBlog}}**{{.Today}}**. {{end}}</textarea>
The following adds a list of links to parent directories. Useful for *view.html*:
<nav>
{{range .Parents}}/ <a href="{{.Url}}">{{.Title}}</a>{{end}}
</nav>
Notes
The templates are always used as-is, irrespective of the current directory. Therefore, a link to a specific page must be *absolute* or it'll point to a different page depending on the current directory.
Consider the link to "/view/index". No matter what page a visitor is looking, this takes visitors to the top "index" page. If the link points to "index" instead, it takes a visitor to the "index" page of the current directory. In this case, a visitor looking at "/view/projects/wiki" following a link to "index" ends up on "/view/projects/index", not on "/view/index".
It's up to you to decide what's best for your site, of course.
If you want a link on *upload.html* to point to the current directory's "index" page, you need to use "/view/{{.Dir}}index" because if you link to "index" the result points to "/upload/{{.Dir}}index".
Templates can be changed by uploading new copies of the template files.
Subdirectories can have their own copies of template files. One example use for this is that they can point to a different CSS file.
See also
oddmu(1)
"Structuring the web with HTML" https://developer.mozilla.org/en-US/docs/Learn/HTML
https://developer.mozilla.org/en-US/docs/Learn/HTML
"Learn to style HTML using CSS" https://developer.mozilla.org/en-US/docs/Learn/CSS
https://developer.mozilla.org/en-US/docs/Learn/CSS
The "text/template" library explains how to write templates from a programmer perspective. https://pkg.go.dev/text/template
https://pkg.go.dev/text/template
The "html/template" library explains how the templates are made more secure in a HTML context. https://pkg.go.dev/html/template
https://pkg.go.dev/html/template
"Lingua" is the library used to detect languages. https://github.com/pemistahl/lingua-go
https://github.com/pemistahl/lingua-go
Authors
Maintained by Alex Schroeder alex@gnu.org.
alex@gnu.org