Before this commit, Hugo used `html/template` for all Go templates.
While this is a fine choice for HTML and maybe also RSS feeds, it is painful for plain text formats such as CSV, JSON etc.
This commit fixes that by using the `IsPlainText` attribute on the output format to decide what to use.
A couple of notes:
* The above requires a nonambiguous template name to type mapping. I.e. `/layouts/_default/list.json` will only work if there is only one JSON output format, `/layouts/_default/list.mytype.json` will always work.
* Ambiguous types will fall back to HTML.
* Partials inherits the text vs HTML identificator of the container template. This also means that plain text templates can only include plain text partials.
* Shortcode templates are, by definition, currently HTML templates only.
Fixes#3221
Before this commit, Hugo used `html/template` for all Go templates.
While this is a fine choice for HTML and maybe also RSS feeds, it is painful for plain text formats such as CSV, JSON etc.
This commit fixes that by using the `IsPlainText` attribute on the output format to decide what to use.
A couple of notes:
* The above requires a nonambiguous template name to type mapping. I.e. `/layouts/_default/list.json` will only work if there is only one JSON output format, `/layouts/_default/list.mytype.json` will always work.
* Ambiguous types will fall back to HTML.
* Partials inherits the text vs HTML identificator of the container template. This also means that plain text templates can only include plain text partials.
* Shortcode templates are, by definition, currently HTML templates only.
Fixes#3221
Add a new rssLimit site configuration option with default of 15. Prior
to this fix, you could create your own RSS feed to override the default
limit of 15, but we still had a hardcoded limit of 50 items set in
`hugolib.renderRSS()`.
With this option in place, the `range first 15 .Data.Pages` logic is no
longer hardcoded into the embedded RSS template.
Because the size of the slice passed to the template is now limited to
rssLimit instead of 50, this commit is a breaking change for sites
with a custom RSS template that expects more than 15 items.
Fixes#3035
Allow all nodes/pages to use date-related OpenGraph meta tags, not
only sites which are using the as-of-yet unfinished .Site.Authors
functionality.
Improve compliance of tags with Facebook's OpenGraph docs for the
"website" and "article" types[0][1]. Also, use the proper tag for
modification date (og:update_time vs article:modified_time).
Generate date published using either .PublishDate or .Date, and use
.Lastmod for modification date, which can use the new enableGitInfo
functionality from Hugo 0.18, but seamlessly falls back to .Date if
the site does not have this enabled/supported.
[0] https://developers.facebook.com/docs/reference/opengraph/object-type/website/
[1] https://developers.facebook.com/docs/reference/opengraph/object-type/article/
Note that this looks like overkill for just the logger, and that is correct,
but this will make sense once we start with the template handling etc.
Updates #2701
This commit adds a truncate template function for safely truncating text without
breaking words. The truncate function is HTML aware, so if the input text is a
template.HTML it will be truncated without leaving broken or unclosed HTML tags.
{{ "this is a very long text" | truncate 10 " ..." }}
{{ "With [Markdown](/markdown) inside." | markdownify | truncate 10 }}
This commit fixes the base template lookup order to match the behaviour of regular templates.
```
1. <current-path>/<template-name>-baseof.<suffix>, e.g. list-baseof.<suffix>.
2. <current-path>/baseof.<suffix>
3. _default/<template-name>-baseof.<suffix>, e.g. list-baseof.<suffix>.
4. _default/baseof.<suffix>
For each of the steps above, it will first look in the project, then, if theme is set,
in the theme's layouts folder.
```
Fixes#2783
There are currently several Params and case related issues floating around in Hugo.
This is very confusing for users and one of the most common support questions on the forum.
And while there have been done some great leg work in Viper etc., this is of limited value since this and similar doesn't work:
`Params.myCamelCasedParam`
Hugo has control over all the template method invocations, and can take care of all the lower-casing of the map lookup keys.
But that doesn't help with direct template lookups of type `Site.Params.TWITTER_CONFIG.USER_ID`.
This commit solves that by doing some carefully crafted modifications of the templates' AST -- lowercasing the params keys.
This is low-level work, but it's not like the template API wil change -- and this is important enough to defend such "bit fiddling".
Tests are added for all the template engines: Go templates, Ace and Amber.
Fixes#2615Fixes#1129Fixes#2590
There are currently several Params and case related issues floating around in Hugo.
This is very confusing for users and one of the most common support questions on the forum.
And while there have been done some great leg work in Viper etc., this is of limited value since this and similar doesn't work:
`Params.myCamelCasedParam`
Hugo has control over all the template method invocations, and can take care of all the lower-casing of the map lookup keys.
But that doesn't help with direct template lookups of type `Site.Params.TWITTER_CONFIG.USER_ID`.
This commit solves that by doing some carefully crafted modifications of the templates' AST -- lowercasing the params keys.
This is low-level work, but it's not like the template API wil change -- and this is important enough to defend such "bit fiddling".
Tests are added for all the template engines: Go templates, Ace and Amber.
Fixes#2615Fixes#1129Fixes#2590
Add imageConfig function which calls image.DecodeConfig and returns the height, width and color mode of the image. (#2677)
This allows for more advanced image shortcodes and templates such as those required by AMP.
layouts/shortcodes/amp-img.html
```
{{ $src := .Get "src" }}
{{ $config := imageConfig (printf "/static/%s" $src) }}
<amp-img src="{{$src}}"
height="{{$config.Height}}"
width="{{$config.Width}}"
layout="responsive">
</amp-img>
```
tpl/template_funcs.go:1019:3: the surrounding loop is unconditionally terminated
source/lazy_file_reader.go:66:5: err != nil is always true for all possible
values ([nil:error] != [nil:error])
All config variables starts with low-case and uses camelCase.
If there is abbreviation at the beginning of the name, the whole
abbreviation will be written in low-case.
If there is abbreviation at the end of the name, the
whole abbreviation will be written in upper-case.
For example, rssURI.
The gain, given the "real sites benchmark" below, is obvious:
```
benchmark old ns/op new ns/op delta
BenchmarkHugo-4 14497594101 13084156335 -9.75%
benchmark old allocs new allocs delta
BenchmarkHugo-4 57404335 48282002 -15.89%
benchmark old bytes new bytes delta
BenchmarkHugo-4 9933505624 9721984424 -2.13%
```
Fixes#2495
* Make the type/var names more specific. They live in the test namespace, but there are other tests there.
* Camel case variable
* Small change suggested by Golint
There were some breaking changes etc. that is too late to fix for 0.17.
Let us think this through and add proper author support for Hugo 0.18.
Fixes#2464
Revert "docs: Add documentation for author profiles"
This reverts commit b6673e5309.
Revert "Add First Class Author Support"
This reverts commit cf978c0649.
* Fall back to default language on missing translation file
* Add a i18n-warnings build flag
* If that flag is set, print a parseable and greppable string on missing translation strings
See #2303
The current "rendering language" is needed outside of Site. This commit moves the Language type to the helpers package, and then used to get correct correct language configuration in the markdownify template func.
This commit also adds two new template funcs: relLangURL and absLangURL.
See #2309
Work In Progress!
This commit makes a rework of the build and rebuild process to better suit a multi-site setup.
This also includes a complete overhaul of the site tests. Previous these were a messy mix that
were testing just small parts of the build chain, some of it testing code-paths not even used in
"real life". Now all tests that depends on a built site follows the same and real production code path.
See #2309Closes#2211Closes#477Closes#1744
This commit also consolidates URLs on Node vs Page, so now .Permalink should be interoperable.
Note that this implementations should be fairly short-livded, waiting for #2297, but the API should be stable.
Setting the language to use when loading the language bundles just doesn't work.
The template system is unfortanetely a global, and the last languate processed won ...
Implements:
* support to render:
* content/post/whatever.en.md to /en/2015/12/22/whatever/index.html
* content/post/whatever.fr.md to /fr/2015/12/22/whatever/index.html
* gets enabled when `Multilingual:` is specified in config.
* support having language switchers in templates, that know
where the translated page is (with .Page.Translations)
(when you're on /en/about/, you can have a "Francais" link pointing to
/fr/a-propos/)
* all translations are in the `.Page.Translations` map, including the current one.
* easily tweak themes to support Multilingual mode
* renders in a single swift, no need for two config files.
Adds a couple of variables useful for multilingual sites
Adds documentation (content/multilingual.md)
Added language prefixing for all URL generation/permalinking see in the
code base.
Implements i18n. Leverages the great github.com/nicksnyder/go-i18n lib.. thanks Nick.
* Adds "i18n" and "T" template functions..
These functions allow trivial escaping and unescaping of HTML entities,
and make it far easier to compose other functions for the creation of
parameterised URLs.
Add logic to tpl.humanize such that it understands input of int literals
or strings which represent an integer. When tpl.humanize sees this type
of input, it will use inflect.Ordinalize as opposed to the standard
inflect.Humanize.
Fixes#1886
The query function will take a set of parameters specified like a dict and return a url.Values object which can be .Encode'd into a query string.
Example:
<a href="http://www.google.com?{{ (querify "q" "test" "page" 3).Encode | safeHTML }}">Search</a>
Returns:
<a href="http://www.google.com?page=3&q=test">Search</a>
Closes#2257
Returns true if a given field value that is a slice / array of strings, integers or floats contains elements in common with the matching value. It follows the same rules as the intersect function.
Closes#1945
While sorting on data sources with missing fields, a panic can occur in
pairList.Less if `Interface()` is called on a invalid `reflect.Value`.
This commit detects an invalid Value and replacing it with a zero value
for the comparison.
This also includes a refactor of the hugofs package and its usage.
The motivation for that is:
The Afero filesystems are brilliant. Hugo's way of adding a dozen of global variables for the different filesystems was a mistake. In readFile (and also in some other places in Hugo today) we need a way to restrict the access inside the working dir. We could use ioutil.ReadFile and implement the path checking, checking the base path and the dots ("..") etc. But it is obviously better to use an Afero BasePathFs combined witha ReadOnlyFs. We could create a use-once-filesystem and handle the initialization ourselves, but since this is also useful to others and the initialization depends on some other global state (which would mean to create a new file system on every invocation), we might as well do it properly and encapsulate the predefined set of filesystems. This change also leads the way, if needed, to encapsulate the file systems in a struct, making it possible to have several file system sets in action at once (parallel multilanguage site building? With Moore's law and all...)
Fixes#1551
To strip away any HTML. May be useful for the .Title in head etc.
People may shoot themself in the foot with this, maybe ...
The replacement function is pretty fast.
The `intersect` function uses `in` to avoid adding duplicates to the
resulting set. We were passing `reflect.Value` items when we should
have been using `Value.Interface()` to send the actual data structure.
This fixes that.
See #1952
This uses the Emoji map from https://github.com/kyokomi/emoji -- but with a custom replacement implementation.
The built-in are fine for most use cases, but in Hugo we do care about pure speed.
The benchmarks below are skewed in Hugo's direction as the source and result is a byte slice,
Kyokomi's implementation works best with strings.
Curious: The easy-to-use `strings.Replacer` is also plenty fast.
```
BenchmarkEmojiKyokomiFprint-4 20000 86038 ns/op 33960 B/op 117 allocs/op
BenchmarkEmojiKyokomiSprint-4 20000 83252 ns/op 38232 B/op 122 allocs/op
BenchmarkEmojiStringsReplacer-4 100000 21092 ns/op 17248 B/op 25 allocs/op
BenchmarkHugoEmoji-4 500000 5728 ns/op 624 B/op 13 allocs/op
```
Fixes#1891
This commit adds a custom index template function that deviates from the stdlib
simply by not returning an "index out of range" error if an array, slice or
string index is out of range. Instead, we just return nil values. This should
help make the new default function more useful for Hugo users.
Fixes#1949
This commit fixes a few things:
1. `given` is now a variadic parameter so that piping works properly
2. add separate template tests to make sure piping works
3. support time values
4. add more tests of the dfault function
The common is the `where` func and this:
```
panic: reflect: call of reflect.Value.Type on zero Value [recovered]
panic: reflect: call of reflect.Value.Type on zero Value
```
There is no good reason to export all the template funcs:
* They're not used outside the templates.
* If usable in other packages, they should be moved (to helpers?)
* They create too broad an interface;
users of the tpl package don't see the forest for all the trees.
Add humanize (inflect.Humanize) to the template funcMap. Documentation and
tests are included.
Various code cleanups of the template funcs:
- Break pluralize and singularize out into stand-alone funcs.
- Sort the list of funcMap entries.
- Add some minimal godoc comments to all public funcs.
- Fix some issues found by golint and grind.
This fixes a exported field check condition in a way described at Go
issue https://golang.org/issue/12367
According to the issue comments, this fix should be safe under Go 1.6.
`where` template function's internal condition check function doesn't
check boolean values and always returns `false` silently.
This adds missing boolean value comparison to the function.
`where Values ".Param.key" true` like clause can be used.
Only "=", "==", "eq", "!=", "<>", "ne" operators are allowed to be used
with a boolean value. If an other operator is passed with it, the
condition check function returns `false` like before.
'sort' template function used to accept only each element's struct field
name, method name and map key name as its second argument. This extends
it to accept a field/method/key chaining key string like
'Params.foo.bar' as the argument. It evaluates sub elements of each
array or map elements and sorts by them.
Typical use case would be sorting pages by user defined front matter
value. For example, sorting pages by 'Params.foo.bar' is possible by
writing the following template code
{{ range sort .Data.Pages "Params.foo.bar" }}
{{ .Content }}
{{ end }}
It ignores all leading and trailing dots so "Params.foo.bar" can be
written in ".Params.foo.bar"
This also fixes the issue that 'sort' cannot evaluate a pointer value.
Fix#1330
sort template function returns `[]interface{}` type slice value
regardless of its original element type.
This fixes it to keep the original element type. For example, if it
sorts `map[string]int` type value, it returns `[]int` slice value
instead of `[]interface{}` slice value.
`where` template function's internal condition check function always
returns `false` when a target value doesn't exist or it's nil value but
this behavior makes it difficult to filter values which doesn't have a
particular parameter.
To solve it, this adds nil value comparison to the function.
`where Values ".Param.key" nil` like clause can be used for the case
above.
Only "=", "==", "eq", "!=", "<>", "ne" operators are allowed to be used
with `nil`. If an other operator is passed with `nil`, the condition
check function returns `false` like before.
Fix#1232
Where `first` will return the first N items of a rangeable list,
`after` will return all items after the Nth item.
This allows the user to do something with the first N items and
something different with the remaining items after N.