Fix for nginx mediatypes, search holder: Update infos for hugo articles

master
Stéphane HUC 2024-02-15 15:05:53 +01:00
parent 7cc40f4724
commit 5ed7c387b9
Signed by: hucste
GPG Key ID: C4ED64222D9B037F
16 changed files with 838 additions and 256 deletions

View File

@ -0,0 +1 @@
["conf/nginx"]

View File

@ -2,14 +2,14 @@ application/atom+xml:
suffixes:
- xml
application/json:
suffixes:
suffixes:
- json
application/opensearchdescription+xml:
suffixes:
suffixes:
- xml
conf/nginx:
suffixes:
- conf
#"conf/nginx":
#suffixes:
#- conf
#text/gemini:
#suffixes:
#- gmi

View File

@ -0,0 +1,7 @@
[nginx]
baseName = "redirections.conf"
isPlainText = true
mediatype = "conf/nginx"
notAlternative = true
path = "nginx-config"

View File

@ -35,15 +35,15 @@ json:
IsPlainText: true
mediaType: application/json
noUgly: false
rel: alternate
nginx:
basename: index
IsHTML: false
isPlainText: true
mediaType: conf/nginx
notAlternative: true
noUgly: true
path: nginx-config
#rel: alternate
#nginx:
#basename: index
#IsHTML: false
#isPlainText: true
#mediaType: conf/nginx
#notAlternative: true
#noUgly: true
#path: nginx-config
opensearch:
basename: opensearch
isHTML: false

View File

@ -46,9 +46,11 @@ The related MimeType to the Opensearch description format is: `application/opens
Since Hugo 0.20, you need to add:
`[mediaTypes]` <br>
`[mediaTypes."application/opensearchdescription+xml"]` <br>
`suffix = "xml"`
```toml
[mediaTypes]
[mediaTypes."application/opensearchdescription+xml"]
suffix = "xml"
```
Here, we added a new type of format for the mime type: `application/opensearchdescription+xml`, with the extension name: `xml`.
@ -56,9 +58,11 @@ Here, we added a new type of format for the mime type: `application/opensearchde
Since Hugo 0.44, you need to add:
`[mediaTypes]` <br>
`[mediaTypes."application/opensearchdescription+xml"]` <br>
`suffixes = ["xml"]`
```toml
[mediaTypes]
[mediaTypes."application/opensearchdescription+xml"]
suffixes = ["xml"]
```
{{< note tip >}}If your old configuration was before the v0.44, you have to transform the variable `suffix` to `suffixes = ['xml']` ! {{< /note >}}
@ -66,18 +70,22 @@ Since Hugo 0.44, you need to add:
The output format declaration to add:
`[outputs]` <br>
`[outputFormats.OpenSearch]` <br>
`baseName = "opensearch"` <br>
`isHTML = false` <br>
`isPlainText = false` <br>
`mediaType = "application/opensearchdescription+xml"` <br>
`noUgly = true` <br>
```toml
[outputs]
[outputFormats.OpenSearch]
baseName = "opensearch"
isHTML = false
isPlainText = false
mediaType = "application/opensearchdescription+xml"
noUgly = true
```
Next, you need to add `"OpenSearch"` at your `home` variable:
`[outputs]` <br>
`home = ["HTML", "OpenSearch"]` <br>
```toml
[outputs]
home = ["HTML", "OpenSearch"]
```
### Template
@ -91,7 +99,27 @@ language are generated.
{{<note info>}}ATTENTION: the presented template manages a multilingual
website. {{</note>}}
{{< file "web-hugo-opensearch-template" xml "layouts/_default/index.opensearch.xml" >}}
```xml
{{ printf `<?xml version="1.0" encoding="utf-8" ?>` | safeHTML }}
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:ie="http://schemas.microsoft.com/Search/2008/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
<Attribution>© {{ $.Date.Format "2006" | safeHTML }} {{ site.Author.name }}; http://creativecommons.org/publicdomain/zero/1.0/legalcode.{{ site.Language.Lang }}</Attribution>
<Contact>{{ site.Author.email | safeHTML }}</Contact>
<Description>{{ i18n "opensearchDescription" }}</Description>
<Developer>{{ site.Author.name | safeHTML }}</Developer>
<InputEncoding>utf-8</InputEncoding>
<Image width="64" height="64" type="image/png">{{ site.BaseURL }}img/Logo-64px.png</Image>
<Image width="16" height="16" type="image/vnd.microsoft.icon">{{ site.BaseURL }}img/favicon.ico</Image>
<Language>{{ site.LanguageCode }}</Language>
<LongName>{{ site.Title }} :: {{ site.Language.Lang }}</LongName>
<OutputEncoding>UTF-8</OutputEncoding>
<ShortName>Websearch</ShortName>
<SyndicationRight>open</SyndicationRight>
<ie:PreviewUrl type="text/html" method="GET" template="{{ site.BaseURL }}{{ site.Language.Lang }}/tags/{searchTerms}/"/>
<moz:SearchForm>{{ site.BaseURL }}{{ site.Language.Lang }}/tags/{searchTerms}/</moz:SearchForm>
<Url template="{{ site.BaseURL }}{{ site.Language.Lang }}/tags/{searchTerms}/" type="text/html" />
<Url rel="self" template="{{ site.BaseURL }}opensearch.xml" type="application/opensearchdescription+xml" />
</OpenSearchDescription>
```
## autodiscovery
@ -105,24 +133,31 @@ Opensearch format description in your web site.
If you have modified your Hugo configuration to generate an {{< inside2 a="atom" l="web:hugo:hugo-feed" t="Atom" >}} feed,
you will need to modify it to add the following:
`<link href="{{ $.Site.BaseURL }}/opensearch.xml" rel="search" type="application/opensearchdescription+xml" title="Websearch" />`
```html
<link href="{{ site.BaseURL }}/opensearch.xml" rel="search" type="application/opensearchdescription+xml" title="Websearch" />
```
### HTML
Add a `link` element:
`<link rel="search" href="/opensearch.xml" title="Websearch" type="application/opensearchdescription+xml">`
```html
<link rel="search" href="/opensearch.xml" title="Websearch" type="application/opensearchdescription+xml">
```
### RSS
If you generate your {{< inside2 a="rss" l="web:hugo:hugo-feed" t="RSS" >}} feed,
make sure to edit it, to add:
* the `xmlns:atom="http://www.w3.org/2005/Atom"` attribute, into your `rss` element: <br>
`<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">`
* in order to declarate `atom:link` item, as: <br>
`<atom:link href="{{ $.Site.BaseURL }}/opensearch.xml" rel="search" type="application/opensearchdescription+xml" title="Websearch" />`
* the `xmlns:atom="http://www.w3.org/2005/Atom"` attribute, into your `rss` element:
```html
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
```
* in order to declarate `atom:link` item, as:
```html
<atom:link href="{{ site.BaseURL }}/opensearch.xml" rel="search" type="application/opensearchdescription+xml" title="Websearch" />
```
----

View File

@ -24,8 +24,10 @@ Let's go back to the code !
Firstly, I write a `$feed` variable; her value is the absolute path for
the file **feed.json**.
`{{- $baseURL := (printf "%s%s/" $.Site.BaseURL $.Site.Language.Lang) | absLangURL -}}` <br>
`{{- $feed := (printf "%s%s" $baseURL "/feed.json") | safeURL -}}`
```hugo
{{- $baseURL := site.BaseURL | absLangURL -}}
{{- $feed := urls.JoinPath $baseURL "/feed.json" | absLangURL -}}
```
### JQuery
@ -34,29 +36,100 @@ will directly call the content returned by the `getJSON` function.
The code:
{{< code "web-hugo-search-jquery-autocomplete-json-code-jqueryui" javascript >}}
```js
{{- with resources.Get $feed -}}
<!-- Javascript -->
<script>
$(function() {
var projects = [
{{- range .items -}}
{
value: "{{ safeHTML .title }}",
label: "{{ safeHTML .summary }}",
url:"{{ safeURL .url }}"
},
{{- end -}}
];
$("#search").autocomplete({
minLength: 0,
source: projects,
focus: function( event, ui ) {
$("#search").val( ui.item.label );
return false;
},
select: function( event, ui ) {
$("#search").val( ui.item.label );
$("#replyer").val( ui.item.value );
return false;
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li>')
.append('<a href="' + item.url + '" alt="'+ item.label + '">' + item.value + '</a>' )
.appendTo(ul);
};
});
</script>
{{- end -}}
```
### HTML
Make HTML is always so simple:
{{< code "web-hugo-search-code-html-input" html >}}
```html
<input class="form-control" id="search" placeholder="{{ T "searchHolderTitle" }}">
<input aria-hidden="true" id="replyer" class="hidden">
```
### TL;DR
{{< file "web-hugo-seach-jquery-autocomplete-json-code-tldr" "search-json.html" html >}}
```html
<div id="search">
<input class="form-control" id="search" placeholder="{{ T "searchHolderTitle" }}">
<input aria-hidden="true" id="replyer" class="hidden">
{{- $baseURL := site.BaseURL | absLangURL -}}
{{- $feed := urls.JoinPath $baseURL "/feed.json" | absLangURL -}}
{{- with resources.Get $feed -}}
<!-- Javascript -->
<script>
$(function() {
var projects = [
{{- range .items -}}
{
value: "{{ safeHTML .title }}",
label: "{{ safeHTML .summary }}",
url:"{{ safeURL .url }}"
},
{{- end -}}
];
$("#search").autocomplete({
minLength: 0,
source: projects,
focus: function( event, ui ) {
$("#search").val( ui.item.label );
return false;
},
select: function( event, ui ) {
$("#search").val( ui.item.label );
$("#replyer").val( ui.item.value );
return false;
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li>')
.append('<a href="' + item.url + '" alt="'+ item.label + '">' + item.value + '</a>' )
.appendTo(ul);
};
});
</script>
{{- end -}}
</div>
```
**Explains** :
The most astute will notice a detail that has its importance:
* **look** the line 3: a condition check if Hugo is on its environment development. <br>
In this case, the code is not builded. <br>
(See section {{< anchor Error error >}} for more informations)
---
Try on the [homepage](/en/), to see the result…
---
Voila!
### Error
@ -65,8 +138,6 @@ it made severals errors, and stop, as: <br>
`ERROR 2020/08/27 08:16:41 Failed to get JSON resource “http://localhost:1313/fr/feed.json”: Get “http://localhost:1313/fr/feed.json”: dial tcp [::1]:1313: connect: connection refused`
{{< abbr A Answer >}}: The server is not able to call a data not builded.
Its the reason why on the final script, there is one condition to check
the environment.
----
@ -75,3 +146,5 @@ the environment.
* {{< gohugo n="search" s="tools" >}}
* Hugo `getJSON` function: {{< gohugo n="data-templates" s="templates" a="load-local-files" >}}
* JQuery UI `autocomplete()` method: https://jqueryui.com/autocomplete
---

View File

@ -13,20 +13,12 @@ Adding a function `search` into static website made with Hugo can be done in dif
We will code this simply with JQuery+UI, in few minutes.
We will use the Hugo `.Site.Pages` variable, and the JQueryUI `autocomplete()` method.
We will use the Hugo `site.Pages` variable, and the JQueryUI `autocomplete()` method.
I assume you known how to add correctly the both JQuery and JQueryUI librairies on your site.
## Codes
### Hugo
To obtain all pages:
{{< code "web-hugo-search-code-hugo" hugo >}}
We create a `$pages` variable that contains all pages informations of the
site. Now, we include it into the code JQuery:
### JQueryUI
As explain into the description section, we use the events of the method `autocomplete()`.
@ -35,14 +27,50 @@ with the Hugo `range` function.
The JQuery code:
{{< code "web-hugo-search-code-jqueryui" javascript >}}
```js
<script>
$(function() {
var projects = [
{{- range site.Pages -}}
{{- $url := .RelPermalink -}}
{{- $title := .LinkTitle -}}
{
value: "{{ $title }}",
label: "{{- if eq $url $baseURL }}{{ site.Params.description }}{{ else if in $url "tags" }}{{- T "pageListTitle" }}{{ $title }}{{ else }}{{- safeHTML .Params.description -}}{{ end -}}",
url:"{{ $url }}"
},
{{- end -}}
];
$("#search").autocomplete({
minLength: 0,
source: projects,
focus: function( event, ui ) {
$("#search").val( ui.item.label );
return false;
},
select: function( event, ui ) {
$("#search").val( ui.item.label );
$("#replyer").val( ui.item.value );
return false;
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li>')
.append('<a href="' + item.url + '" alt="'+ item.label + '">' + item.value + '</a>' )
.appendTo(ul);
};
});
</script>
```
### HTML
And for the simplest code HTML, we use two elements `input` as:
{{< code "web-hugo-search-code-html-input" html >}}
```html
<input class="form-control" id="search" placeholder="{{ T "searchHolderTitle" }}">
<input aria-hidden="true" id="replyer" class="hidden">
```
* the first catch the searched text
* the second return all found titles, and in the background the equivalent URL.
@ -53,14 +81,58 @@ And for the simplest code HTML, we use two elements `input` as:
The fully code:
{{< code "web-hugo-search-code-tldr" html >}}
```html
<div id="search">
<input class="form-control" id="search" placeholder="{{ T "searchHolderTitle" }}">
<input aria-hidden="true" id="replyer" class="hidden">
{{- $baseURL := site.BaseURL | absLangURL -}}
<!-- Javascript -->
<script>
$(function() {
var projects = [
{{- range site.Pages -}}
{{- $url := .RelPermalink -}}
{{- $title := .LinkTitle -}}
{
value: "{{ $title }}",
label: "{{- if eq $url $baseURL }}{{ site.Params.description }}{{ else if in $url "tags" }}{{- T "pageListTitle" }}{{ $title }}{{ else }}{{- safeHTML .Params.description -}}{{ end -}}",
url:"{{ $url }}"
},
{{- end -}}
];
$("#search").autocomplete({
minLength: 0,
source: projects,
focus: function( event, ui ) {
$("#search").val( ui.item.label );
return false;
},
select: function( event, ui ) {
$("#search").val( ui.item.label );
$("#replyer").val( ui.item.value );
return false;
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li>')
.append('<a href="' + item.url + '" alt="'+ item.label + '">' + item.value + '</a>' )
.appendTo(ul);
};
});
</script>
</div>
```
---
## Demo
Voilà ! <br>
In few minutes, an "internal search engine" is born on your static website Hugo.
Actually, on the [homepage](/en/), it's this {{< inside "web/hugo/hugo-search-jqueryui-autocomplete-json" "modified code" >}} running…
See, the search holder on the menu navigation, at top right side ;)
----
---
## Documentation
@ -75,5 +147,4 @@ Actually, on the [homepage](/en/), it's this {{< inside "web/hugo/hugo-search-jq
* More explains about JQueryUI `Autocomplete()` method: See the [documentation](https://www.tutorialspoint.com/jqueryui/jqueryui_autocomplete.htm)
* Another method to [build internal search engine](https://en.jeffprod.com/blog/2018/build-your-own-hugo-website-search-engine/), with VueJS + Axios librairies
----
---

View File

@ -9,9 +9,13 @@ tags: ["Hugo","Feed","RSS","Atom","JSON"]
## Description
Parmi les flux de données, {{< tag Hugo >}} est capable de créer plusieurs flux dont {{< abbr RSS "Really Simple Syndication" >}} *(actuellement, à la norme 2.0)*.
Parmi les flux de données, {{< tag Hugo >}} est capable de créer plusieurs
flux dont {{< abbr RSS "Really Simple Syndication" >}}
*(actuellement, à la norme 2.0)*.
**Hugo** est donc capable de générer un flux {{< anchor RSS rss >}}, ou de type {{< anchor JSON json >}}, mais pas {{< anchor ATOM atom >}} - *pour ce dernier, nous verrons comment faire dans le chapitre ad hoc*.
**Hugo** est donc capable de générer un flux {{< anchor RSS rss >}}, ou
de type {{< anchor JSON json >}}, mais pas {{< anchor ATOM atom >}} -
*pour ce dernier, nous verrons comment faire dans le chapitre ad hoc*.
## Documentation
@ -26,89 +30,139 @@ Un petit tour sur la documentation officielle Hugo :
## Détails Techniques
Commençons par les détails techniques suivants à-propos de la gestion de différents éléments ; chaque format de flux a ses propres spécificités, certaines sont communes ou peuvent se ressembler. Merci de lire les {{< anchor RFC "documentations tierces" >}} adéquates.
Commençons par les détails techniques suivants à-propos de la gestion de
différents éléments ; chaque format de flux a ses propres spécificités,
certaines sont communes ou peuvent se ressembler. Merci de lire les
{{< anchor RFC "documentations tierces" >}} adéquates.
### author
Les trois formats de flux gérent un élément `author` dans les différentes entrées générées. Quant à l'auteur du site, là où ATOM et JSON ont leur élément `author` avec leurs spécificités, RSS a son propre élément `managingEditor`, voire `webMaster`.
Les trois formats de flux gérent un élément `author` dans les différentes
entrées générées. Quant à l'auteur du site, là où ATOM et JSON ont leur
élément `author` avec leurs spécificités, RSS a son propre élément
`managingEditor`, voire `webMaster`.
Il faut configurer le bloc `author` dans le fichier de configuration, de telle manière : <br>
`[author]` <br>
`email = "courriel@domaine.tld"` <br>
`name = "Nom Prénom"`
Il faut configurer le bloc `author` dans le fichier de configuration,
de telle manière :
```toml
[params]
[params.author]
email = "courriel@domaine.tld"
name = "Nom Prénom"
```
### category
Là où ATOM et RSS sont capables de générer un élément `catégory`, JSON utilise l'élément `tag`.
Là où ATOM et RSS sont capables de générer un élément `catégory`, JSON
utilise l'élément `tag`.
Dans tous les cas, j'ai utilisé la taxonomie des tags pour les créer.
Il faut configurer la taxonomie dans le fichier de configuration, de telle manière : <br>
`[taxonomies]` <br>
`tag = "tags"`
Il faut configurer la taxonomie dans le fichier de configuration, de
telle manière :
```toml
[taxonomies]
tag = "tags"
```
### copyright
Là où RSS a son élément `copyright`,
* ATOM peut annoncer par le biais d'un élément `link` qui permet de cibler un fichier de licence - *telle une licence {{< abbr CC "Creatives Commons" >}}* - ainsi que son élément `rights`.
* ATOM peut annoncer par le biais d'un élément `link` qui permet de
cibler un fichier de licence - *telle une licence {{< abbr CC "Creatives Commons" >}}* -
ainsi que son élément `rights`.
* JSON n'a rien de prévu.
Il faut configurer la variable `copyright` dans le fichier de configuration.
### description
Là où RSS et JSON ont leur élément `description` du flux, ATOM n'en a pas, mais il est possible d'utiliser l'élément `subtitle`.
Là où RSS et JSON ont leur élément `description` du flux, ATOM n'en a pas,
mais il est possible d'utiliser l'élément `subtitle`.
Concernant l'usage de l'élément `description`, j'utilise personnellement la variable `.Site.Params.description`.
Concernant l'usage de l'élément `description`, j'utilise personnellement
la variable `site.Params.description`.
Il faut configurer la variable `description` dans le fichier de configuration.
### generator
Seul ATOM et RSS sont capables de générer un élément `generator`, bien qu'ATOM le fasse plus finement.
Seul ATOM et RSS sont capables de générer un élément `generator`, bien
qu'ATOM le fasse plus finement.
On peut utiliser les variables spécifiques à Hugo.
### id
Pour RSS, l'identifiant d'une entrée est l'élément `guid`. ATOM et JSON ont un élément `id` . ATOM a aussi son identifiant de site.
Pour RSS, l'identifiant d'une entrée est l'élément `guid`. ATOM et JSON
ont un élément `id` . ATOM a aussi son identifiant de site.
Il est important de veiller à ce que cet identifiant soit unique ; il y a plusieurs manières de les générer :
Il est important de veiller à ce que cet identifiant soit unique ; il y
a plusieurs manières de les générer :
* Soit tout simplement par le biais de l'URL du site, ou de l'article correspondant à l'entrée : <br> `<id>{{ .Permalink }}</id>`
* Soit en utilisant le schéma de notation `tag`, définie par la RFC 4151, de type `tag:identifiant,DATE:alphanumerique` et où `tag:identifiant,DATE` ne doit pas changer sur l'ensemble du site, seule la partie `alphanumerique` sera l'objet de l'unicité de l'article ou de l'identifiant du site :
* où l'identifiant peut être soit une adresse mail, soit le nom de domaine ; ce dernier semble être la préférence.
* où DATE doit correspondre à la norme ISO 8601, à minima l'année, codée sur 4 chiffres, telle que `2019` ; la préférence peut être donnée à la forme `YYYY-MM-DD` où l'année, le mois et le jour sont séparés par un tiret `-`, telle que `2019-10-07` qui peut correspondre à la date de création de votre domaine, par exemple.
* Soit tout simplement par le biais de l'URL du site, ou de l'article
correspondant à l'entrée : <br> `<id>{{ .Permalink }}</id>`
* Soit en utilisant le schéma de notation `tag`, définie par la RFC 4151,
de type `tag:identifiant,DATE:alphanumerique` et où `tag:identifiant,DATE`
ne doit pas changer sur l'ensemble du site, seule la partie `alphanumerique`
sera l'objet de l'unicité de l'article ou de l'identifiant du site :
* où l'identifiant peut être soit une adresse mail, soit le nom de
domaine ; ce dernier semble être la préférence.
* où DATE doit correspondre à la norme ISO 8601, à minima l'année,
codée sur 4 chiffres, telle que `2019` ; la préférence peut être
donnée à la forme `YYYY-MM-DD` où l'année, le mois et le jour
sont séparés par un tiret `-`, telle que `2019-10-07` qui peut
correspondre à la date de création de votre domaine, par exemple.
* où `alphanumerique` est un ensemble de lettres et de chiffres.
* Pour exemple :
* Pour l'identifiant du site : `{{ $url := urls.Parse .Permalink }}{{ $id := print "tag:" $url.Host ",2019-10-07:" }}<id>{{ $id }}website</id>`
* Pour l'identifiant d'entrée : `<id>{{ $id }}{{ anchorize .RelPermalink }}</id>`
* Pour RSS, remplacez la balise `<id>` par `<guid>`. De même, si vous utilisez la notation par tag ou par UURI, il vous faudra ajouter l'attribut `isPermalink`, tel que : `isPermaLink="false"`
* Soit en utilisant le schéma de notation `UURI` définie par la RFC 4122 - *qui est humainement incompréhensible* ; l'avantage avec Hugo est qu'on peut la générer dynamiquement en utilisant la fonction `sha`, tout particulièrement `sha1` conforme à la version 5 de ladite numérotation, telle que : <br> `{{ $uuid := sha1 .Permalink }}<id>urn:uuid:{{substr $uuid 0 8}}-{{substr $uuid 10 4}}-{{substr $uuid 15 4}}-{{substr $uuid 20 4}}-{{substr $uuid 25 12}}</id>`
* Pour l'identifiant du site :
`{{ $url := urls.Parse .Permalink }}{{ $id := print "tag:" $url.Host ",2019-10-07:" }}<id>{{ $id }}website</id>`
* Pour l'identifiant d'entrée :
`<id>{{ $id }}{{ anchorize .RelPermalink }}</id>`
* Pour RSS, remplacez la balise `<id>` par `<guid>`.
De même, si vous utilisez la notation par tag ou par UURI,
il vous faudra ajouter l'attribut `isPermalink`, tel que :
`isPermaLink="false"`
* Soit en utilisant le schéma de notation `UURI` définie par la RFC 4122 -
*qui est humainement incompréhensible* ; l'avantage avec Hugo est qu'on
peut la générer dynamiquement en utilisant la fonction `sha`, tout
particulièrement `sha1` conforme à la version 5 de ladite numérotation,
telle que :
```hugo
{{ $uuid := sha1 .Permalink }}<id>urn:uuid:{{substr $uuid 0 8}}-{{substr $uuid 10 4}}-{{substr $uuid 15 4}}-{{substr $uuid 20 4}}-{{substr $uuid 25 12}}</id>
```
### image
Là où RSS gère l'élément `image` pour afficher le logo,
* ATOM et JSON gèrent deux éléments différents, `icon` pour l'image de favicon, et `logo` pour votre… logo !
* ATOM et JSON gèrent deux éléments différents, `icon` pour l'image de
favicon, et `logo` pour votre… logo !
* JSON est capable, en plus, de gérer un avatar pour l'auteur.
### Limite
{{< note warning >}}Il semble nécessaire d'utiliser au moins Hugo v0.55.x{{< /note >}}
Le code Hugo suivant, *que j'utilise dans chacun des modèles*, permet de limiter le nombre d'entrées selon :
Le code Hugo suivant, *que j'utilise dans chacun des modèles*, permet de
limiter le nombre d'entrées selon :
* La limite du service RSS,
* Si les pages ont le paramètre `disable_feed` sur `true`, elles ne sont pas incluses.
* Si les pages ont le paramètre `disable_feed` sur `true`, elles ne sont
pas incluses.
* On capture le nombre de pages,
* Puis on utilise la fonction Hugo `range` pour générer dynamiquement le nombre d'entrées - *l'usage de la fonction dans le modèle pour JSON différe légérement de celui pour les modèles ATOM et RSS* - :
`{{- $limit := (cond (le .Site.Config.Services.RSS.Limit 0) 65536 .Site.Config.Services.RSS.Limit) -}}` <br>
`{{- $pages := where .Site.RegularPages ".Params.disable_feed" "!=" true -}}` <br>
`{{- if ge $limit 1 -}}{{- $pages = $pages | first $limit -}}{{- end -}}` <br>
* Puis on utilise la fonction Hugo `range` pour générer dynamiquement le
nombre d'entrées - *l'usage de la fonction dans le modèle pour JSON
différe légérement de celui pour les modèles ATOM et RSS* - :
```hugo
{{- $limit := (cond (le site.Config.Services.RSS.Limit 0) 65536 site.Config.Services.RSS.Limit) -}}
{{- $pages := where site.RegularPages ".Params.disable_feed" "!=" true -}}
{{- if ge $limit 1 -}}{{- $pages = $pages | first $limit -}}{{- end -}}
```
## Configuration
@ -116,26 +170,76 @@ Le code Hugo suivant, *que j'utilise dans chacun des modèles*, permet de limite
### RSS
{{< note info >}}Il est possible de spécifier dans le fichier de configuration le format de sortie RSS pour `home`, `section` et les deux `taxonomy`, `taxonomyTerm`.{{< /note >}}
{{< note info >}}Il est possible de spécifier dans le fichier de
configuration le format de sortie RSS pour `home`, `section` et les deux
`taxonomy`, `taxonomyTerm`.{{< /note >}}
Personnellement, je renomme le nom du flux RSS en modifiant dans le fichier de configuration, la variable `baseName` à `rss` parce que je ne pense pas que celui-ci doit porter le nom `index`. En effet, le nom `rss.xml` est plus parlant !
Personnellement, je renomme le nom du flux RSS en modifiant dans le
fichier de configuration, la variable `baseName` à `rss` parce que je ne
pense pas que celui-ci doit porter le nom `index`.
`[outputs]` <br>
`home = ["HTML", "RSS"]` <br>
`[outputFormats.RSS]` <br>
`baseName = "rss"`
En effet, le nom `rss.xml` est plus parlant !
{{< note info >}}Sachez qu'il est possible de surcharger la génération native du flux RSS, en créant un modèle dans `_default`. {{< /note >}}
```toml
[outputs]
home = ["HTML", "RSS"]
[outputFormats.RSS]
baseName = "rss"
```
{{< note info >}}Sachez qu'il est possible de surcharger la génération
native du flux RSS, en créant un modèle dans `_default`. {{< /note >}}
#### RSS:Template
{{< note warning >}}Il n'est pas nécessaire de créer ce modèle du fait que Hugo génére correctement, mais pour de l'anglais, le fichier RSS, nommé `index.xml`.{{< /note >}}
{{< note warning >}}Il n'est pas nécessaire de créer ce modèle du fait
que Hugo génére correctement, mais pour de l'anglais, le fichier RSS,
nommé `index.xml`.{{< /note >}}
J'ai créé mon propre modèle, tenant compte du fait d'être multilangue.
----
{{< file "web-hugo-feed-template-rss" xml "layouts/_default/rss.xml" >}}
```xml
{{ printf `<?xml version="1.0" encoding="utf-8" standalone="yes" ?>` | safeHTML }}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ if eq .Title site.Title }}{{ site.Title }}{{ else }}{{ with .Title }}{{.}}{{ T "on" }}{{ end }}'{{ site.Title }}'{{ end }}</title>
<link>{{ .Permalink }}</link>
{{ with site.Params.description -}}<description>{{ . }}</description>{{- end }}
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>Hugo {{ Hugo.Version }}</generator>
<image>
<description>Logo</description>
<height>128</height>
<link>{{ .Permalink }}</link>
<title>{{ if eq .Title site.Title }}{{ site.Title }}{{ else }}{{ with .Title }}{{.}}{{ T "on" }}{{ end }}'{{ site.Title }}'{{ end }}</title>
<url>{{ site.BaseURL }}img/Logo.png</url>
<width>128</width>
</image>
{{ with site.LanguageCode }}<language>{{.}}</language>{{end}}
{{ with site.Params.author.email }}<managingEditor>{{.}}{{ with site.Params.author.name }} ({{.}}){{end}}</managingEditor>
<webMaster>{{.}}{{ with site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}
{{ with site.Copyright }}<copyright>© {{ $.Date.Format "2006" | safeHTML }} {{ site.Author.name }}; {{.}}</copyright>{{end}}
{{ if not .Date.IsZero }}<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
{{ with .OutputFormats.Get "RSS" }}{{ printf `<atom:link href=%q rel="self" type=%q />` .Permalink .MediaType | safeHTML }}{{ end }}
{{- $limit := (cond (le site.Config.Services.RSS.Limit 0) 65536 site.Config.Services.RSS.Limit) -}}
{{- $pages := where site.Pages ".Params.disable_feed" "!=" true -}}
{{- if ge $limit 1 -}}{{- $pages = $pages | first $limit -}}{{- end -}}
{{- range first $limit $pages }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
{{ with .Summary }}<description>{{ . | html }}</description>{{end}}
{{ with site.Params.author.email }}<author>{{.}}{{ with site.Params.author.name }} ({{.}}){{end}}</author>{{end}}{{ $url := printf "%s" "/tags/" | absLangURL }}
{{ with .Params.tags }}{{ range . }}<category domain="{{ $url }}{{urlize .}}/">{{.}}</category>{{end}}{{end}}
<guid>{{ .Permalink }}</guid>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
</item>
{{ end }}
</channel>
</rss>
```
### Atom
@ -152,46 +256,107 @@ Il est nécessaire de modifier le fichier de configuration pour :
##### Hugo >= 0.20
Depuis Hugo 0.20, il faut ajouter :
`[mediaTypes]` <br>
`[mediaTypes."application/atom+xml"]` <br>
`suffix = "xml"`
```toml
[mediaTypes]
[mediaTypes."application/atom+xml"]
suffix = "xml"
```
Là, nous avons donc implémenté un nouveau type de format ayant pour mime type : `application/atom+xml`, et pour nom d'extension : `xml`.
Là, nous avons donc implémenté un nouveau type de format ayant pour mime
type : `application/atom+xml`, et pour nom d'extension : `xml`.
##### Hugo >= 0.44
Depuis Hugo 0.44, pour que cela fonctionne correctement il faut ajouter :
`[mediaTypes]` <br>
`[mediaTypes."application/atom+xml"]` <br>
`suffixes = ["xml"]`
```toml
[mediaTypes]
[mediaTypes."application/atom+xml"]
suffixes = ["xml"]
```
{{< note tip >}}Si votre ancienne configuration précédait la 0.44, il faut adapter/transformer la variable `suffix` en `suffixes = ['xml']` ! {{< /note >}}
{{< note tip >}}Si votre ancienne configuration précédait la 0.44, il
faut adapter/transformer la variable `suffix` en `suffixes = ['xml']` !
{{< /note >}}
#### Atom::OuputFormat
La déclaration du format de sortie, à ajouter :
`[outputs]` <br>
`[outputFormats.Atom]` <br>
`baseName = "atom"` <br>
`isPlainText = false` <br>
`mediaType = "application/atom+xml"` <br>
```toml
[outputFormats.Atom]
baseName = "atom"
isPlainText = false
mediaType = "application/atom+xml"
```
Puis, il faut ajouter `"ATOM"` à votre variable `home`, tel que :
`[outputs]` <br>
`home = ["HTML", "ATOM", "RSS"]`
```toml
[outputs]
home = ["HTML", "ATOM", "RSS"]
```
#### Atom::Template
Le modèle peut simplement être créé dans le répertoire `layouts/` et se nommer `index.atom.xml`, ou être dans son sous-répertoire `_default/` et se nommer, par exemple : `home.atom.xml`.
Le modèle peut simplement être créé dans le répertoire `layouts/` et se
nommer `index.atom.xml`, ou être dans son sous-répertoire `_default/` et
se nommer, par exemple : `home.atom.xml`.
* Si le site est multilangue, les liens alternatifs vers la version de langue correspondante à l'entrée du site, aux flux atom, RSS, voire JSON sont générés.
* Si le site est multilangue, les liens alternatifs vers la version de
langue correspondante à l'entrée du site, aux flux atom, RSS, voire JSON
sont générés.
----
{{< file "web-hugo-feed-template-atom" xml "layouts/_default/home.atom.xml" >}}
```xml
{{ printf `<?xml version="1.0" encoding="utf-8" standalone="yes" ?>` | safeHTML }}
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="{{ with site.Language.Lang }}{{.}}{{end}}">
<id>{{ .Permalink }}</id>
<title>{{ if eq .Title site.Title }}{{ site.Title }}{{ else }}{{ with .Title }}{{.}}{{ T "on" }}{{ end }}'{{ site.Title }}'{{ end }}</title>
{{ with site.Params.description -}}<subtitle>{{ . }}</subtitle>{{- end }}
{{ with .OutputFormats.Get "ATOM" }}{{ printf `<link href=%q rel="self" type=%q />` .Permalink .MediaType | safeHTML }}{{end}}
{{ range .AlternativeOutputFormats -}}
<link href="{{ if eq .Name "HTML" }}{{ $.Permalink }}{{ else }}{{ printf `%s%s.%s` $.Permalink (.Name | lower) (index .MediaType.Suffixes 0) }}{{end}}" rel="alternate" {{ printf "type=%q" .MediaType.Type | safeHTMLAttr }} />
{{end}}{{ if site.IsMultiLingual }}{{ range site.Languages }}{{ if ne .Lang site.Language.Lang }}{{ $lang := .Lang }}
{{ with $.OutputFormats.Get "ATOM" }}{{ printf `<link href=%q hreflang=%q rel="alternate" type=%q />` (print $lang "/" .Name "." (index .MediaType.Suffixes 0) |absURL) $lang .MediaType | safeHTML }}{{end}}
{{ range $.AlternativeOutputFormats -}}
<link href="{{ if eq .Name "HTML" }}{{ printf `%s/` $lang | absURL }}{{ else }}{{ printf `%s/%s.%s` $lang (.Name | lower) (index .MediaType.Suffixes 0) | absURL }}{{end}}" hreflang="{{ $lang }}" rel="alternate" {{ printf "type=%q" .MediaType.Type | safeHTMLAttr }} />
{{end}}{{end}}{{end}}{{end}}{{ with site.Copyright }}{{ $lang := site.Language.Lang }}
<link href="http://creativecommons.org/publicdomain/zero/1.0/legalcode.{{ $lang }}" hreflang="{{ $lang }}" rel="license" />
<link href="http://creativecommons.org/publicdomain/zero/1.0/deed.{{ $lang }}" hreflang="{{ $lang }}" rel="license" />
<rights>© {{ $.Date.Format "2006" | safeHTML }} {{ site.Params.author.name }}</rights>{{end}}
<icon>/img/favicon.ico</icon>
{{ with site.Params.logo }}<logo>{{.}}</logo>{{end}}
{{ if not .Date.IsZero }}<updated>{{ .Date.Format "2006-01-02T15:04:05-07:00" | safeHTML }}</updated>{{ end }}
{{ with site.Params.author.name }}
<author>
<name>{{.}}</name>
{{ with site.Params.author.email }}<email>{{.}}</email>{{end}}
<uri>{{ $.Permalink }}</uri>
</author>{{end}}
<generator uri="https://gohugo.io" version="{{ Hugo.Version }}">Hugo</generator>
{{- $limit := (cond (le site.Config.Services.RSS.Limit 0) 65536 site.Config.Services.RSS.Limit) -}}
{{- $pages := where site.RegularPages ".Params.disable_feed" "!=" true -}}
{{- if ge $limit 1 -}}{{- $pages = $pages | first $limit -}}{{- end -}}
{{- range first $limit $pages }}
<entry>
<id>{{ .Permalink }}</id>
<link href="{{ .Permalink }}" rel="alternate" type="text/html" />
<title>{{ .Title }}</title>{{ with site.Params.author }}
<author>
<name>{{.}}</name>
</author>{{end}}{{ $url := printf "%s" "/tags/" | absLangURL }}{{ with .Params.tags }}{{ range . }}
<category term="{{.}}" scheme="{{ print $url (urlize .) | absLangURL }}/" />{{end}}
{{end}}
{{ with .Content }}<content type="html">{{ `<![CDATA[` | safeHTML }}{{.}}]]></content>{{end}}
{{ with .Summary }}<summary type="html">{{ `<![CDATA[` | safeHTML }}{{.}}]]></summary>{{end}}
<published>{{ .Date.Format "2006-01-02T15:04:05-07:00" | safeHTML }}</published>
{{ if gt .Lastmod .Date }}<updated>{{ .Lastmod.Format "2006-01-02T15:04:05-07:00" | safeHTML }}</updated>{{end}}
</entry>
{{ end }}
</feed>
```
### JSON
@ -201,38 +366,80 @@ Pour générer le flux JSON, nous nous conformerons à la norme JSON Feed v1.
La déclaration de sortie de format à ajouter :
`[outputs]` <br>
`[outputFormats.JSON]` <br>
`mediaType = "application/json"` <br>
`baseName = "feed"` <br>
`suffix = "json"` <br>
`IsHTML = false` <br>
`IsPlainText = true` <br>
`noUgly = false` <br>
`rel = "alternate"`
```toml
[outputFormats.JSON]
mediaType = "application/json"
baseName = "feed"
suffix = "json"
IsHTML = false
IsPlainText = true
noUgly = false
rel = "alternate"
```
Puis, il faut ajouter la déclaration `JSON` à votre variable `home`, tel que :
`[outputs]` <br>
`home = ["HTML", "ATOM", "JSON", "RSS"]`
```toml
[outputs]
`home = ["HTML", "ATOM", "JSON", "RSS"]
```
#### JSON::Template
##### JSON: Détails
En plus de la {{< anchor limite limite >}} mentionnée plus haut, nous récupèrons le nombre de page, pour boucler correctement car le dernier `item` ne doit pas être suivi du symbole ',' :
`{{- $length := (len $pages) -}}`
En plus de la {{< anchor limite limite >}} mentionnée plus haut, nous
récupèrons le nombre de page, pour boucler correctement car le dernier
`item` ne doit pas être suivi du symbole ',' :
```hugo
{{- $length := (len $pages) -}}
```
Et en fin de boucle `range`, nous ajoutons :
```hugo
{{ if ne (add $index 1) $length }},{{ end }}
```
Ainsi tant qu'il y a un élément suivant, il est précédé du symbole ','
jusqu'au dernier.
`{{ if ne (add $index 1) $length }},{{ end }}`
---
Ainsi tant qu'il y a un élément suivant, il est précédé du symbole ',' jusqu'au dernier.
____
{{< file "web-hugo-feed-template-json" json "layouts/index.json" >}}
```json
{{- $limit := (cond (le site.Config.Services.RSS.Limit 0) 65536 site.Config.Services.RSS.Limit) -}}
{{- $pages := where site.RegularPages ".Params.disable_feed" "!=" true -}}
{{- if ge $limit 1 -}}{{- $pages = $pages | first $limit -}}{{- end -}}
{{- $length := (len $pages) -}}
{
"version": "https://jsonfeed.org/version/1",
"title": "{{ site.Title }}",
"home_page_url": "{{ site.BaseURL }}",
{{ with .OutputFormats.Get "JSON" -}}"feed_url": "{{.Permalink}}",{{- end }}
{{ with site.Params.description -}}"description": "{{ . }}",{{- end }}
{{ with site.Params.author.name }}
"author": {
"avatar": "{{ with site.Params.logo }}{{ . }}{{ end}}",
"name": "{{ . }}",
"url": "http://huc.fr.eu.org"
},
{{- end }}
{{ with site.Params.logo }}"icon": "{{ . }}",{{- end }}
"favicon": "/img/favicon.ico",
"items": [ {{- range $index, $elements := $pages -}}
{
"id": "{{ .Permalink }}",
"url": "{{ .Permalink }}",
"title": "{{ .Title | plainify }}",
{{ with site.Params.Author }}"author": { "name": "{{ . }}" }{{ end }}{{ with .Content }},
"content_text": {{ . | plainify | jsonify }},
"content_html": {{ . | safeHTML | jsonify }}{{ end }}{{ with .Summary }},
"summary": {{ . | plainify | jsonify }}{{ end }}{{ with .Params.tags }},
"tags": [{{ range $tindex, $tag := . }}{{ if $tindex }}, {{ end }}"{{ $tag| htmlEscape }}"{{ end }}]{{ end }}{{ if .PublishDate }},
"date_published": "{{ .PublishDate.Format "2006-01-02T15:04:05-01:00" | safeHTML }}"{{ end }}{{ if gt .Lastmod .Date }},
"date_modified": "{{ .Lastmod.Format "2006-01-02T15:04:05-01:00" | safeHTML }}"{{ end }}
}{{ if ne (add $index 1) $length }},{{ end }}{{- end }}
]
}
```
## Documentations tierces

View File

@ -48,9 +48,11 @@ Le type mime lié au format de description d'Opensearch est : `application/opens
Depuis Hugo 0.20, il faut ajouter :
`[mediaTypes]` <br>
`[mediaTypes."application/opensearchdescription+xml"]` <br>
`suffix = "xml"`
```toml
[mediaTypes]
[mediaTypes."application/opensearchdescription+xml"]
suffix = "xml"
```
Là, nous avons donc implémenté un nouveau type de format ayant pour mime type : `application/opensearchdescription+xml`, et pour nom d'extension : `xml`.
@ -58,9 +60,11 @@ Là, nous avons donc implémenté un nouveau type de format ayant pour mime type
Depuis Hugo 0.44, pour que cela fonctionne correctement il faut ajouter :
`[mediaTypes]` <br>
`[mediaTypes."application/opensearchdescription+xml"]` <br>
`suffixes = ["xml"]`
```toml
[mediaTypes]
[mediaTypes."application/opensearchdescription+xml"]
suffixes = ["xml"]
```
{{< note tip >}}Si votre ancienne configuration précédait la 0.44, il faut adapter/transformer la variable `suffix` en `suffixes = ['xml']` ! {{< /note >}}
@ -68,18 +72,22 @@ Depuis Hugo 0.44, pour que cela fonctionne correctement il faut ajouter :
La déclaration du format de sortie, à ajouter :
`[outputs]` <br>
`[outputFormats.OpenSearch]` <br>
`baseName = "opensearch"` <br>
`isHTML = false` <br>
`isPlainText = false` <br>
`mediaType = "application/opensearchdescription+xml"` <br>
`noUgly = true` <br>
```toml
[outputs]
[outputFormats.OpenSearch]
baseName = "opensearch"
isHTML = false
isPlainText = false
mediaType = "application/opensearchdescription+xml"
noUgly = true
```
Puis, il faut ajouter `"OpenSearch"` à votre variable `home`, tel que :
`[outputs]` <br>
`home = ["HTML", "OpenSearch"]` <br>
```toml
[outputs]
home = ["HTML", "OpenSearch"]
```
### Template
@ -95,7 +103,27 @@ Tenez-en compte, en supprimant les déclarations de langue, si ce n'est
pas votre cas.
{{</note>}}
{{< file "web-hugo-opensearch-template" xml "layouts/_default/index.opensearch.xml" >}}
```xml
{{ printf `<?xml version="1.0" encoding="utf-8" ?>` | safeHTML }}
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:ie="http://schemas.microsoft.com/Search/2008/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
<Attribution>© {{ $.Date.Format "2006" | safeHTML }} {{ site.Author.name }}; http://creativecommons.org/publicdomain/zero/1.0/legalcode.{{ site.Language.Lang }}</Attribution>
<Contact>{{ site.Author.email | safeHTML }}</Contact>
<Description>{{ i18n "opensearchDescription" }}</Description>
<Developer>{{ site.Author.name | safeHTML }}</Developer>
<InputEncoding>utf-8</InputEncoding>
<Image width="64" height="64" type="image/png">{{ site.BaseURL }}img/Logo-64px.png</Image>
<Image width="16" height="16" type="image/vnd.microsoft.icon">{{ site.BaseURL }}img/favicon.ico</Image>
<Language>{{ site.LanguageCode }}</Language>
<LongName>{{ site.Title }} :: {{ site.Language.Lang }}</LongName>
<OutputEncoding>UTF-8</OutputEncoding>
<ShortName>Websearch</ShortName>
<SyndicationRight>open</SyndicationRight>
<ie:PreviewUrl type="text/html" method="GET" template="{{ site.BaseURL }}{{ site.Language.Lang }}/tags/{searchTerms}/"/>
<moz:SearchForm>{{ site.BaseURL }}{{ site.Language.Lang }}/tags/{searchTerms}/</moz:SearchForm>
<Url template="{{ site.BaseURL }}{{ site.Language.Lang }}/tags/{searchTerms}/" type="text/html" />
<Url rel="self" template="{{ site.BaseURL }}opensearch.xml" type="application/opensearchdescription+xml" />
</OpenSearchDescription>
```
## autopublication
@ -110,23 +138,31 @@ l'élément `ShortName` !{{</note>}}
Si vous avez modifié votre configuration de Hugo pour générer un flux {{< inside2 a="atom" l="web:hugo:hugo-feed" t="Atom" >}}
il vous faudra le modifier pour ajouter ce qui suit :
`<link href="{{ $.Site.BaseURL }}/opensearch.xml" rel="search" type="application/opensearchdescription+xml" title="Websearch" />`
```html
<link href="{{ site.BaseURL }}/opensearch.xml" rel="search" type="application/opensearchdescription+xml" title="Websearch" />
```
### HTML
Ajouter un élément `link`, tel que :
`<link rel="search" href="/opensearch.xml" title="Websearch" type="application/opensearchdescription+xml">`
```html
<link rel="search" href="/opensearch.xml" title="Websearch" type="application/opensearchdescription+xml">
```
### RSS
Si vous générez votre flux {{< inside2 a="rss" l="web:hugo:hugo-feed" t="RSS" >}}, veillez à le modifier pour ajouter :
* la déclaration de l'attribut `xmlns:atom="http://www.w3.org/2005/Atom"`
dans votre élément `rss`, tel que : <br>
`<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">`
* afin de pouvoir déclarer un élément `atom:link`, tel que : <br>
`<atom:link href="{{ $.Site.BaseURL }}/opensearch.xml" rel="search" type="application/opensearchdescription+xml" title="Websearch" />`
dans votre élément `rss`, tel que :
```html
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
```
* afin de pouvoir déclarer un élément `atom:link`, tel que :
```html
<atom:link href="{{ site.BaseURL }}/opensearch.xml" rel="search" type="application/opensearchdescription+xml" title="Websearch" />
```
----

View File

@ -21,6 +21,10 @@ Hugo a une fonction native `getJSON`.
Reprenons le code…
{{< note warning >}}
Ne fonctionne pas en environnement de développement !
{{</note>}}
## Code
### Hugo
@ -28,8 +32,10 @@ Reprenons le code…
Je construis une variable `$feed` qui injectera la valeur du chemin absolu
de mon fichier **feed.json**.
`{{- $baseURL := (printf "%s%s/" $.Site.BaseURL $.Site.Language.Lang) | absLangURL -}}` <br>
`{{- $feed := (printf "%s%s" $baseURL "/feed.json") | safeURL -}}`
```hugo
{{- $baseURL := site.BaseURL | absLangURL -}}
{{- $feed := urls.JoinPath $baseURL "/feed.json" | absLangURL -}}
```
### JQuery
@ -40,41 +46,114 @@ par la fonction `getJSON`. La suite du traitement est faite par la méthode
Voici le code :
{{< code "web-hugo-search-jquery-autocomplete-json-code-jqueryui" javascript >}}
```js
{{- with resources.Get $feed -}}
<!-- Javascript -->
<script>
$(function() {
var projects = [
{{- range .items -}}
{
value: "{{ safeHTML .title }}",
label: "{{ safeHTML .summary }}",
url:"{{ safeURL .url }}"
},
{{- end -}}
];
$("#search").autocomplete({
minLength: 0,
source: projects,
focus: function( event, ui ) {
$("#search").val( ui.item.label );
return false;
},
select: function( event, ui ) {
$("#search").val( ui.item.label );
$("#replyer").val( ui.item.value );
return false;
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li>')
.append('<a href="' + item.url + '" alt="'+ item.label + '">' + item.value + '</a>' )
.appendTo(ul);
};
});
</script>
{{- end -}}
```
### HTML
La partie de code HTML est toujours aussi simple :
{{< code "web-hugo-search-code-html-input" html >}}
```html
<input class="form-control" id="search" placeholder="{{ T "searchHolderTitle" }}">
<input aria-hidden="true" id="replyer" class="hidden">
```
### TL;DR
L'ensemble du code :
{{< file "web-hugo-seach-jquery-autocomplete-json-code-tldr" "search-json.html" html >}}
```html
<div id="search">
<input class="form-control" id="search" placeholder="{{ T "searchHolderTitle" }}">
<input aria-hidden="true" id="replyer" class="hidden">
{{- $baseURL := site.BaseURL | absLangURL -}}
{{- $feed := urls.JoinPath $baseURL "/feed.json" | absLangURL -}}
{{- with resources.Get $feed -}}
<!-- Javascript -->
<script>
$(function() {
var projects = [
{{- range .items -}}
{
value: "{{ safeHTML .title }}",
label: "{{ safeHTML .summary }}",
url:"{{ safeURL .url }}"
},
{{- end -}}
];
$("#search").autocomplete({
minLength: 0,
source: projects,
focus: function( event, ui ) {
$("#search").val( ui.item.label );
return false;
},
select: function( event, ui ) {
$("#search").val( ui.item.label );
$("#replyer").val( ui.item.value );
return false;
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li>')
.append('<a href="' + item.url + '" alt="'+ item.label + '">' + item.value + '</a>' )
.appendTo(ul);
};
});
</script>
{{- end -}}
</div>
```
**Explications** :
---
Les plus avisés remarqueront un détail qui a son importance :
* **regardez bien** la ligne trois, j'ai implémenté une condition qui teste si on est dans
l'environnement de développement local, si oui le code n'est pas généré. <br>
Pour l'explication, lire la section {{< anchor Erreur erreur >}}…
Voilà !
---
Pour ce qui est de la démonstration, c'est ce qu'il y a sur la [page d'accueil](/fr/) de ce site ;)
### Erreur
{{< abbr Q Question >}} : Lors de la génération en local, vous avez une multitude d'erreur, telle
que la suivante et le serveur s'arrête tout seul : <br>
{{< abbr Q Question >}} : Lors de la génération en local, vous avez une
multitude d'erreur, telle que la suivante et le serveur s'arrête
tout seul : <br>
`ERROR 2020/08/27 08:16:41 Failed to get JSON resource “http://localhost:1313/fr/feed.json”: Get “http://localhost:1313/fr/feed.json”: dial tcp [::1]:1313: connect: connection refused`
{{< abbr R Réponse >}} : Et, oui, en local, le serveur n'est pas capable d'appeler une donnée qui
n'est pas encore générée. C'est pourquoi dans le script final, une condition
est imbriquée pour vérifier l'environnement de création.
{{< abbr R Réponse >}} : En environnement local, le serveur n'est pas
capable d'appeler une donnée qui n'est pas encore générée.
----
@ -83,3 +162,5 @@ est imbriquée pour vérifier l'environnement de création.
* La documentation officielle : {{< gohugo n="search" s="tools" >}} - *lien en anglais*
* La fonction Hugo `getJSON` : {{< gohugo n="data-templates" s="templates" a="load-local-files" >}} - *lien en anglais*
* La méthode JQuery UI `autocomplete()` : https://jqueryui.com/autocomplete - *lien en anglais*
---

View File

@ -9,41 +9,80 @@ translationKey: "hugo-jqueryui-autocomplete"
## Description
Intégrer une fonction de recherche au sein du site généré par Hugo peut se faire de différentes manières.
Intégrer une fonction de recherche au sein du site généré par Hugo peut
se faire de différentes manières.
On va implémenter une manière très simple avec JQuery+UI, et cela nous prendra vraiment très peu de temps.
On va implémenter une manière très simple avec JQuery+UI, et cela nous
prendra vraiment très peu de temps.
Étant donné qu'on peut parcourir l'ensemble des pages du site grâce à la variable `.Site.Pages`, on va se servir du mécanisme de la méthode `autocomplete()` fournie par la bibliothèque JQueryUI, pour restituer les différents résultats selon le texte écrit.
Étant donné qu'on peut parcourir l'ensemble des pages du site grâce à
la variable globale `site.Pages`, on va se servir du mécanisme de la
méthode `autocomplete()` fournie par la bibliothèque JQueryUI, pour
restituer les différents résultats selon le texte écrit.
Bien sûr, j'assume le fait que vous savez intégrer les appels de scripts JQuery et JQueryUI au sein de votre propre site.
Bien sûr, j'assume le fait que vous savez intégrer les appels de scripts
JQuery et JQueryUI au sein de votre propre site.
## Codes
### Hugo
Pour récupèrer les pages en codant Hugo :
{{< code "web-hugo-search-code-hugo" hugo >}}
Nous créeons une variable `$pages` qui contient l'ensemble des pages du site, que nous allons inclure dans le code JQuery.
### JQueryUI
Pour la partie JQuery, nous utilisons la gestion des événements de la méthode `autocomplete()`, à la différence près est que la variable `var projects` va être implémentée par le biais de la fonction Hugo `range` appliquée sur la variable `$pages`.
Pour la partie JQuery, nous utilisons la gestion des événements de la
méthode `autocomplete()`, à la différence près est que la variable
`projects` va être implémentée par le biais de la fonction Hugo `range`.
Le code JQuery :
{{< code "web-hugo-search-code-jqueryui" javascript >}}
```js
<script>
$(function() {
var projects = [
{{- range site.Pages -}}
{{- $url := .RelPermalink -}}
{{- $title := .LinkTitle -}}
{
value: "{{ $title }}",
label: "{{- if eq $url $baseURL }}{{ site.Params.description }}{{ else if in $url "tags" }}{{- T "pageListTitle" }}{{ $title }}{{ else }}{{- safeHTML .Params.description -}}{{ end -}}",
url:"{{ $url }}"
},
{{- end -}}
];
$("#search").autocomplete({
minLength: 0,
source: projects,
focus: function( event, ui ) {
$("#search").val( ui.item.label );
return false;
},
select: function( event, ui ) {
$("#search").val( ui.item.label );
$("#replyer").val( ui.item.value );
return false;
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li>')
.append('<a href="' + item.url + '" alt="'+ item.label + '">' + item.value + '</a>' )
.appendTo(ul);
};
});
</script>
```
### HTML
Quant à la partie HTML, elle est très simple ; il faut à minima les deux éléments `input` suivants :
Quant à la partie HTML, elle est très simple ; il faut à minima les deux
éléments `input` suivants :
{{< code "web-hugo-search-code-html-input" html >}}
```html
<input class="form-control" id="search" placeholder="{{ T "searchHolderTitle" }}">
<input aria-hidden="true" id="replyer" class="hidden">
```
* Le premier élément `input` est celui qui "capte" le texte recherché
* le second va permettre de retourner les informations trouvées.
* La déclaration Hugo `{{ i18n "searchHolderTitle" }}` est juste pour le contexte multilangue de ce site ; à remplacer par du texte selon votre goût…
* La déclaration Hugo `{{ i18n "searchHolderTitle" }}` est juste pour le
contexte multilangue de ce site ; à remplacer par du texte selon votre goût…
Que vous faites suivre du code Hugo puis du code JQuery
@ -51,20 +90,59 @@ Que vous faites suivre du code Hugo puis du code JQuery
L'ensemble du code :
{{< code "web-hugo-search-code-tldr" html >}}
```html
<div id="search">
<input class="form-control" id="search" placeholder="{{ T "searchHolderTitle" }}">
<input aria-hidden="true" id="replyer" class="hidden">
{{- $baseURL := site.BaseURL | absLangURL -}}
<!-- Javascript -->
<script>
$(function() {
var projects = [
{{- range site.Pages -}}
{{- $url := .RelPermalink -}}
{{- $title := .LinkTitle -}}
{
value: "{{ $title }}",
label: "{{- if eq $url $baseURL }}{{ site.Params.description }}{{ else if in $url "tags" }}{{- T "pageListTitle" }}{{ $title }}{{ else }}{{- safeHTML .Params.description -}}{{ end -}}",
url:"{{ $url }}"
},
{{- end -}}
];
$("#search").autocomplete({
minLength: 0,
source: projects,
focus: function( event, ui ) {
$("#search").val( ui.item.label );
return false;
},
select: function( event, ui ) {
$("#search").val( ui.item.label );
$("#replyer").val( ui.item.value );
return false;
}
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
return $('<li>')
.append('<a href="' + item.url + '" alt="'+ item.label + '">' + item.value + '</a>' )
.appendTo(ul);
};
});
</script>
</div>
```
Et, voilà ! <br>
En quelques minutes, un "moteur de recherche" interne intégré à votre site Hugo.
*Les plus attentifs remarqueront de subtiles différences entre ce code entier
et les explications ci-dessus… <br>
Je vous laisse chercher !* ;-)
---
Pour ce qui est de la démonstration, c'est ce qu'il y avait sur la [page d'accueil](/) de ce site. <br>
Maintenant, c'est la version appelant le flux de syndication JSON qui
fonctionne. *(cf : {{< inside "web/hugo/hugo-search-jqueryui-autocomplete-json" "" >}}* !
## Démonstration
----
Pour ce qui est de la démonstration, c'est ce qu'il y a dans le menu,
en haut à droite de chacune des pages du site.
---
## Documentations
@ -75,5 +153,4 @@ fonctionne. *(cf : {{< inside "web/hugo/hugo-search-jqueryui-autocomplete-json"
* De plus amples explications sur la méthode `Autocomplete()` de JQueryUI : lire la [documentation](https://www.tutorialspoint.com/jqueryui/jqueryui_autocomplete.htm) - *lien en anglais*
* Une autre méthode de [moteur de recherche interne](https://fr.jeffprod.com/blog/2018/un-moteur-de-recherche-interne-pour-votre-site-hugo/), cette fois-ci avec les bibliothèques VueJS + Axios
----
---

View File

@ -28,8 +28,8 @@ Le principe est l'utilisation des alias d'URL.
En partant du principe de l'utilisation du format toml, ouvrez le fichier que vous voulez rediriger et dans son entête, ajoutez :
```cfg
aliases: [/ancienne/URL/de/publication/fichier/]
```toml
aliases = [/ancienne/URL/de/publication/fichier/]
```
*Si votre format de fichier de configuration est autre, adaptez !*
@ -41,13 +41,13 @@ suivantes :
⇒ Ajoutez un type de media
```cfg
```toml
[mediaTypes."conf/nginx"]
```
⇒ Ajoutez une sortie à générer, pour la variable **home** :
```cfg
```toml
[outputs]
home = ["HTML", "nginx", …]
```
@ -55,7 +55,7 @@ suivantes :
⇒ Ajoutez la sortie du format adéquat pour créer le fichier de redirections
pour nginx :
```cfg
```toml
[outputFormats.nginx]
baseName = "redirections.conf"
isPlainText = true
@ -70,11 +70,10 @@ Puis, créer le **layout** nécessaire : `layout/index.nginx`, tel que :
```cfg
# Nginx redirect
{{ range $p := .Site.Pages -}}
{{ range .Aliases }}
rewrite ^{{ . }}$ {{ $p.RelPermalink }} permanent;
{{ end -}}
{{- end -}}
{{- range $p := site.Pages -}}
{{- range .Aliases }}
rewrite ^{{ . }}$ {{ $p.RelPermalink }} permanent;{{ end }}
{{- end }}
```
---
@ -102,7 +101,7 @@ nginx: [emerg] open() "/var/www/htdocs/doc.huc.fr.eu.org/www/fr/nginx-conf/redir
Et, oui le fichier existe bien, au bon endroit :
```
```sh
$ ls -al /var/www/htdocs/doc.huc.fr.eu.org/www/fr/nginx-config/redirections.conf
-rw-r--r-- 1 www www 397 Jul 28 13:23 /var/www/htdocs/doc.huc.fr.eu.org/www/fr/nginx-config/redirections.conf
```

View File

@ -1,6 +1,5 @@
# Nginx redirect
{{ range $p := site.Pages -}}
{{ range .Aliases }}
rewrite ^{{ . }}$ {{ $p.RelPermalink }} permanent;
{{ end -}}
{{- end -}}
{{- range $p := site.Pages -}}
{{- range .Aliases }}
rewrite ^{{ . }}$ {{ $p.RelPermalink }} permanent;{{ end }}
{{- end }}

View File

@ -59,8 +59,9 @@
{{ partial "utils/icon" (dict "$" $.Dot "name" "search" "class" "post-meta-icon") }}
<input class="form-control" id="search" placeholder="{{ T "searchHolderTitle" }}">
<input aria-hidden="true" id="replyer" class="hidden" hidden>
{{- if eq hugo.Environment "development" -}}{{ partial "utils/search.js" (dict "Dot" .Dot) }}{{ else }}{{ partial "utils/search.json" (dict "Dot" .Dot) }}{{- end -}}
</li>
{{/* if eq hugo.Environment "development" -}}{{ partial "utils/search.js" . }}{{ else }}{{ partial "utils/search.json" . }}{{- end */}}
{{- partial "utils/search.js" . -}}
</li>
</ul>
{{- end -}}
</nav>

View File

@ -1,14 +1,11 @@
{{- $baseURL := (partial "func/baseURL" .) | relLangURL -}}
<!-- Javascript -->
{{- $currentNode := . -}}
{{- $currentNode.Scratch.Set "pages" site.Pages -}}
{{- $pages := ($currentNode.Scratch.Get "pages") -}}
{{- $baseURL := (partial "func/baseURL" .) | absLangURL -}}
<script>
$(function() {
var projects = [
{{- range $pages -}}
{{- $url := .Permalink | safeURL -}}
{{- $title := safeHTML .Title -}}
{{- range site.Pages -}}
{{- $url := .RelPermalink -}}
{{- $title := .LinkTitle -}}
{
value: "{{ $title }}",
label: "{{- if eq $url $baseURL }}{{ site.Params.description }}{{ else if in $url "tags" }}{{- T "pageListTitle" }}{{ $title }}{{ else }}{{- safeHTML .Params.description -}}{{ end -}}",

View File

@ -1,22 +1,17 @@
{{- $baseURL := (partial "func/baseURL" .) | absLangURL -}}
{{- $feed := urls.JoinPath $baseURL "/feed.json" | absLangURL -}}{{ $feed }}
{{- with resources.Get $feed -}}
<!-- Javascript -->
<script>
{{/* $baseURL := (printf "%s%s" $.Site.BaseURL $.Site.Language.Lang) | absLangURL */}}
{{- $baseURL := (partial "func/baseURL" .) | absLangURL -}}
{{- $feed := (printf "%s%s" $baseURL "/feed.json") | safeURL -}}
$(function() {
var projects = [
{{- with getJSON $feed -}}
{{- range .items -}}
{{- $url := safeURL .url -}}
{{- $title := safeHTML .title -}}
{{- $desc := safeHTML .summary -}}
{{- range .items -}}
{
value: "{{ $title }}",
label: "{{ $desc }}",
url:"{{ $url }}"
value: "{{ safeHTML .title }}",
label: "{{ safeHTML .summary }}",
url:"{{ safeURL .url }}"
},
{{- end -}}
{{- end -}}
];
$("#search").autocomplete({
minLength: 0,
@ -38,3 +33,6 @@ $(function() {
};
});
</script>
{{- else -}}
<!-- unavailable resource {{ $feed }} -->
{{- end -}}