mirror of
https://github.com/gohugoio/hugoDocs.git
synced 2025-09-10 10:44:43 -04:00
Update link render hook to support glossary links
This commit is contained in:
parent
53eadb430f
commit
cd95f0f34e
@ -331,6 +331,22 @@ Use the glossary link (`gl`) shortcode to insert a link to the given glossary te
|
|||||||
|
|
||||||
{{% gl scalar %}}
|
{{% gl scalar %}}
|
||||||
|
|
||||||
|
Note that this site's link render hook provides a custom syntax to insert a link to the given glossary term. This method of linking to a glossary term is easier to both read and write:
|
||||||
|
|
||||||
|
```text
|
||||||
|
[scalar](g) <-- the g stands for glossary
|
||||||
|
```
|
||||||
|
|
||||||
|
[scalar](g)
|
||||||
|
|
||||||
|
With both methods you can use either the singular or plural form of the term:
|
||||||
|
|
||||||
|
```text
|
||||||
|
{{%/* gl scalars */%}} and [scalars](g)
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% gl scalars %}} and [scalars](g)
|
||||||
|
|
||||||
### glossary term
|
### glossary term
|
||||||
|
|
||||||
Use the glossary term (`gt`) shortcode to insert the definition of the given glossary term.
|
Use the glossary term (`gt`) shortcode to insert the definition of the given glossary term.
|
||||||
|
@ -148,7 +148,7 @@ In your base template, conditionally include the KaTeX CSS within the head eleme
|
|||||||
</head>
|
</head>
|
||||||
{{< /code >}}
|
{{< /code >}}
|
||||||
|
|
||||||
In the above, note the use of a {{% gl noop %}} statement to force content rendering before we check the value of `hasMath` with the `Store.Get` method.
|
In the above, note the use of a [noop](g) statement to force content rendering before we check the value of `hasMath` with the `Store.Get` method.
|
||||||
|
|
||||||
#### Step 4
|
#### Step 4
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ Then, in your base template, conditionally include the KaTeX CSS within the head
|
|||||||
</head>
|
</head>
|
||||||
{{< /code >}}
|
{{< /code >}}
|
||||||
|
|
||||||
In the above, note the use of a {{% gl noop %}} statement to force content rendering before we check the value of `hasMath` with the `Store.Get` method.
|
In the above, note the use of a [noop](g) statement to force content rendering before we check the value of `hasMath` with the `Store.Get` method.
|
||||||
|
|
||||||
Although you can use one template with conditional logic as shown above, you can also create separate templates for each [`Type`](#type) of passthrough element:
|
Although you can use one template with conditional logic as shown above, you can also create separate templates for each [`Type`](#type) of passthrough element:
|
||||||
|
|
||||||
|
319
layouts/_default/_markup/render-link.html
Normal file
319
layouts/_default/_markup/render-link.html
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
{{- /* Last modified: 2025-01-19T14:44:56-08:00 */}}
|
||||||
|
|
||||||
|
{{- /*
|
||||||
|
Copyright 2025 Veriphor LLC
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
the License at
|
||||||
|
|
||||||
|
https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations under
|
||||||
|
the License.
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{- /*
|
||||||
|
This render hook resolves internal destinations by looking for a matching:
|
||||||
|
|
||||||
|
1. Content page
|
||||||
|
2. Page resource (a file in the current page bundle)
|
||||||
|
3. Section resource (a file in the current section)
|
||||||
|
4. Global resource (a file in the assets directory)
|
||||||
|
|
||||||
|
It skips the section resource lookup if the current page is a leaf bundle.
|
||||||
|
|
||||||
|
External destinations are not modified.
|
||||||
|
|
||||||
|
You must place global resources in the assets directory. If you have placed
|
||||||
|
your resources in the static directory, and you are unable or unwilling to move
|
||||||
|
them, you must mount the static directory to the assets directory by including
|
||||||
|
both of these entries in your site configuration:
|
||||||
|
|
||||||
|
[[module.mounts]]
|
||||||
|
source = 'assets'
|
||||||
|
target = 'assets'
|
||||||
|
|
||||||
|
[[module.mounts]]
|
||||||
|
source = 'static'
|
||||||
|
target = 'assets'
|
||||||
|
|
||||||
|
By default, if this render hook is unable to resolve a destination, including a
|
||||||
|
fragment if present, it passes the destination through without modification. To
|
||||||
|
emit a warning or error, set the error level in your site configuration:
|
||||||
|
|
||||||
|
[params.render_hooks.link]
|
||||||
|
errorLevel = 'warning' # ignore (default), warning, or error (fails the build)
|
||||||
|
|
||||||
|
When you set the error level to warning, and you are in a development
|
||||||
|
environment, you can visually highlight broken internal links:
|
||||||
|
|
||||||
|
[params.render_hooks.link]
|
||||||
|
errorLevel = 'warning' # ignore (default), warning, or error (fails the build)
|
||||||
|
highlightBroken = true # true or false (default)
|
||||||
|
|
||||||
|
This will add a "broken" class to anchor elements with invalid src attributes.
|
||||||
|
Add a rule to your CSS targeting the broken links:
|
||||||
|
|
||||||
|
a.broken {
|
||||||
|
background: #ff0;
|
||||||
|
border: 2px solid #f00;
|
||||||
|
padding: 0.1em 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
This render hook may be unable to resolve destinations created with the ref and
|
||||||
|
relref shortcodes. Unless you set the error level to ignore you should not use
|
||||||
|
either of these shortcodes in conjunction with this render hook.
|
||||||
|
|
||||||
|
@context {string} Destination The link destination.
|
||||||
|
@context {page} Page A reference to the page containing the link.
|
||||||
|
@context {string} PlainText The link description as plain text.
|
||||||
|
@context {string} Text The link description.
|
||||||
|
@context {string} Title The link title.
|
||||||
|
|
||||||
|
@returns {template.html}
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{- /* Initialize. */}}
|
||||||
|
{{- $renderHookName := "link" }}
|
||||||
|
|
||||||
|
{{- /* Verify minimum required version. */}}
|
||||||
|
{{- $minHugoVersion := "0.141.0" }}
|
||||||
|
{{- if lt hugo.Version $minHugoVersion }}
|
||||||
|
{{- errorf "The %q render hook requires Hugo v%s or later." $renderHookName $minHugoVersion }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Error level when unable to resolve destination: ignore, warning, or error. */}}
|
||||||
|
{{- $errorLevel := or site.Params.render_hooks.link.errorLevel "ignore" | lower }}
|
||||||
|
|
||||||
|
{{- /* If true, adds "broken" class to broken links. Applicable in development environment when errorLevel is warning. */}}
|
||||||
|
{{- $highlightBrokenLinks := or site.Params.render_hooks.link.highlightBroken false }}
|
||||||
|
|
||||||
|
{{- /* Validate error level. */}}
|
||||||
|
{{- if not (in (slice "ignore" "warning" "error") $errorLevel) }}
|
||||||
|
{{- errorf "The %q render hook is misconfigured. The errorLevel %q is invalid. Please check your site configuration." $renderHookName $errorLevel }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Determine content path for warning and error messages. */}}
|
||||||
|
{{- $contentPath := .Page.String }}
|
||||||
|
|
||||||
|
{{- /* Parse destination. */}}
|
||||||
|
{{- $u := urls.Parse .Destination }}
|
||||||
|
|
||||||
|
{{- /* Set common message. */}}
|
||||||
|
{{- $msg := printf "The %q render hook was unable to resolve the destination %q in %s" $renderHookName $u.String $contentPath }}
|
||||||
|
|
||||||
|
{{- /* Set attributes for anchor element. */}}
|
||||||
|
{{- $attrs := dict "href" $u.String }}
|
||||||
|
{{- if eq $u.String "g" }}
|
||||||
|
{{- /* Destination is a glossary term. */}}
|
||||||
|
{{- $ctx := dict
|
||||||
|
"contentPath" $contentPath
|
||||||
|
"errorLevel" $errorLevel
|
||||||
|
"renderHookName" $renderHookName
|
||||||
|
"text" .Text
|
||||||
|
}}
|
||||||
|
{{- $attrs = partial "inline/h-rh-l/get-glossary-link-attributes.html" $ctx }}
|
||||||
|
{{- else if $u.IsAbs }}
|
||||||
|
{{- /* Destination is a remote resource. */}}
|
||||||
|
{{- $attrs = merge $attrs (dict "rel" "external") }}
|
||||||
|
{{- else }}
|
||||||
|
{{- with $u.Path }}
|
||||||
|
{{- with $p := or ($.PageInner.GetPage .) ($.PageInner.GetPage (strings.TrimRight "/" .)) }}
|
||||||
|
{{- /* Destination is a page. */}}
|
||||||
|
{{- $href := .RelPermalink }}
|
||||||
|
{{- with $u.RawQuery }}
|
||||||
|
{{- $href = printf "%s?%s" $href . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with $u.Fragment }}
|
||||||
|
{{- $ctx := dict
|
||||||
|
"contentPath" $contentPath
|
||||||
|
"errorLevel" $errorLevel
|
||||||
|
"page" $p
|
||||||
|
"parsedURL" $u
|
||||||
|
"renderHookName" $renderHookName
|
||||||
|
}}
|
||||||
|
{{- partial "inline/h-rh-l/validate-fragment.html" $ctx }}
|
||||||
|
{{- $href = printf "%s#%s" $href . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $attrs = dict "href" $href }}
|
||||||
|
{{- else with $.PageInner.Resources.Get $u.Path }}
|
||||||
|
{{- /* Destination is a page resource; drop query and fragment. */}}
|
||||||
|
{{- $attrs = dict "href" .RelPermalink }}
|
||||||
|
{{- else with (and (ne $.Page.BundleType "leaf") ($.Page.CurrentSection.Resources.Get $u.Path)) }}
|
||||||
|
{{- /* Destination is a section resource, and current page is not a leaf bundle. */}}
|
||||||
|
{{- $attrs = dict "href" .RelPermalink }}
|
||||||
|
{{- else with resources.Get $u.Path }}
|
||||||
|
{{- /* Destination is a global resource; drop query and fragment. */}}
|
||||||
|
{{- $attrs = dict "href" .RelPermalink }}
|
||||||
|
{{- else }}
|
||||||
|
{{- if eq $errorLevel "warning" }}
|
||||||
|
{{- warnf $msg }}
|
||||||
|
{{- if and $highlightBrokenLinks hugo.IsDevelopment }}
|
||||||
|
{{- $attrs = merge $attrs (dict "class" "broken") }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else if eq $errorLevel "error" }}
|
||||||
|
{{- errorf $msg }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{- with $u.Fragment }}
|
||||||
|
{{- /* Destination is on the same page; prepend relative permalink. */}}
|
||||||
|
{{- $ctx := dict
|
||||||
|
"contentPath" $contentPath
|
||||||
|
"errorLevel" $errorLevel
|
||||||
|
"page" $.Page
|
||||||
|
"parsedURL" $u
|
||||||
|
"renderHookName" $renderHookName
|
||||||
|
}}
|
||||||
|
{{- partial "inline/h-rh-l/validate-fragment.html" $ctx }}
|
||||||
|
{{- $attrs = dict "href" (printf "%s#%s" $.Page.RelPermalink .) }}
|
||||||
|
{{- else }}
|
||||||
|
{{- if eq $errorLevel "warning" }}
|
||||||
|
{{- warnf $msg }}
|
||||||
|
{{- if and $highlightBrokenLinks hugo.IsDevelopment }}
|
||||||
|
{{- $attrs = merge $attrs (dict "class" "broken") }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else if eq $errorLevel "error" }}
|
||||||
|
{{- errorf $msg }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Render anchor element. */ -}}
|
||||||
|
<a
|
||||||
|
{{- with .Title }} title="{{ . }}" {{- end }}
|
||||||
|
{{- range $k, $v := $attrs }}
|
||||||
|
{{- if $v }}
|
||||||
|
{{- printf " %s=%q" $k ($v | transform.HTMLEscape) | safeHTMLAttr }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end -}}
|
||||||
|
>{{ .Text }}</a>
|
||||||
|
|
||||||
|
{{- define "partials/inline/h-rh-l/validate-fragment.html" }}
|
||||||
|
{{- /*
|
||||||
|
Validates the fragment portion of a link destination.
|
||||||
|
|
||||||
|
@context {string} contentPath The page containing the link.
|
||||||
|
@context {string} errorLevel The error level when unable to resolve destination; ignore (default), warning, or error.
|
||||||
|
@context {page} page The page corresponding to the link destination
|
||||||
|
@context {struct} parsedURL The link destination parsed by urls.Parse.
|
||||||
|
@context {string} renderHookName The name of the render hook.
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{- /* Initialize. */}}
|
||||||
|
{{- $contentPath := .contentPath }}
|
||||||
|
{{- $errorLevel := .errorLevel }}
|
||||||
|
{{- $p := .page }}
|
||||||
|
{{- $u := .parsedURL }}
|
||||||
|
{{- $renderHookName := .renderHookName }}
|
||||||
|
|
||||||
|
{{- /* Validate. */}}
|
||||||
|
{{- with $u.Fragment }}
|
||||||
|
{{- if $p.Fragments.Identifiers.Contains . }}
|
||||||
|
{{- if gt ($p.Fragments.Identifiers.Count .) 1 }}
|
||||||
|
{{- $msg := printf "The %q render hook detected duplicate heading IDs %q in %s" $renderHookName . $contentPath }}
|
||||||
|
{{- if eq $errorLevel "warning" }}
|
||||||
|
{{- warnf $msg }}
|
||||||
|
{{- else if eq $errorLevel "error" }}
|
||||||
|
{{- errorf $msg }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{- /* Determine target path for warning and error message. */}}
|
||||||
|
{{- $targetPath := "" }}
|
||||||
|
{{- with $p.File }}
|
||||||
|
{{- $targetPath = .Path }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $targetPath = .Path }}
|
||||||
|
{{- end }}
|
||||||
|
{{- /* Set common message. */}}
|
||||||
|
{{- $msg := printf "The %q render hook was unable to find heading ID %q in %s. See %s" $renderHookName . $targetPath $contentPath }}
|
||||||
|
{{- if eq $targetPath $contentPath }}
|
||||||
|
{{- $msg = printf "The %q render hook was unable to find heading ID %q in %s" $renderHookName . $targetPath }}
|
||||||
|
{{- end }}
|
||||||
|
{{- /* Throw warning or error. */}}
|
||||||
|
{{- if eq $errorLevel "warning" }}
|
||||||
|
{{- warnf $msg }}
|
||||||
|
{{- else if eq $errorLevel "error" }}
|
||||||
|
{{- errorf $msg }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "partials/inline/h-rh-l/get-glossary-link-attributes.html" }}
|
||||||
|
{{- /*
|
||||||
|
Returns the anchor element attributes for a link to the given glossary term.
|
||||||
|
|
||||||
|
It first checks for the existence of a glossary page for the given term. If
|
||||||
|
no page is found, it then checks for a glossary page for the singular form of
|
||||||
|
the term. If neither page exists it throws a warning or error dependent on
|
||||||
|
the errorLevel setting
|
||||||
|
|
||||||
|
The returned href attribute does not point to the glossary term page.
|
||||||
|
Instead, via its fragment, it points to an entry on the glossary page.
|
||||||
|
|
||||||
|
@context {string} contentPath The page containing the link.
|
||||||
|
@context {string} errorLevel The error level when unable to resolve destination; ignore (default), warning, or error.
|
||||||
|
@context {string} renderHookName The name of the render hook.
|
||||||
|
@context {string} text The link text.
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{- /* Get context.. */}}
|
||||||
|
{{- $contentPath := .contentPath }}
|
||||||
|
{{- $errorLevel := .errorLevel }}
|
||||||
|
{{- $renderHookName := .renderHookName }}
|
||||||
|
{{- $text := .text }}
|
||||||
|
|
||||||
|
{{- /* Initialize. */}}
|
||||||
|
{{- $basePath := "/getting-started/glossary" }}
|
||||||
|
{{- $termGiven := $text }}
|
||||||
|
{{- $termActual := "" }}
|
||||||
|
{{- $termSingular := inflect.Singularize $termGiven }}
|
||||||
|
|
||||||
|
{{- /* Validate the base path. */}}
|
||||||
|
{{- if not (site.GetPage $basePath) }}
|
||||||
|
{{- $msg := printf "The %q render hook was unable to find %s: see %s" $renderHookName $basePath $contentPath }}
|
||||||
|
{{- if eq $errorLevel "warning" }}
|
||||||
|
{{- warnf $msg }}
|
||||||
|
{{- else if eq $errorLevel "error" }}
|
||||||
|
{{- errorf $msg }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Verify that a glossary term page exists for the given term. */}}
|
||||||
|
{{- if site.GetPage (urls.JoinPath $basePath $termGiven) }}
|
||||||
|
{{- $termActual = $termGiven }}
|
||||||
|
{{- else if site.GetPage (urls.JoinPath $basePath $termSingular) }}
|
||||||
|
{{- $termActual = $termSingular}}
|
||||||
|
{{- else }}
|
||||||
|
{{- $msg := printf "The %q render hook was unable to find a defintion for either the singular or plural form of the term %q: see %s" $renderHookName $termGiven $contentPath }}
|
||||||
|
{{- if eq $errorLevel "warning" }}
|
||||||
|
{{- warnf $msg }}
|
||||||
|
{{- else if eq $errorLevel "error" }}
|
||||||
|
{{- errorf $msg }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Create the href attribute. */}}
|
||||||
|
{{- $href := ""}}
|
||||||
|
{{- if $termActual }}
|
||||||
|
{{- with site.GetPage $basePath }}
|
||||||
|
{{- $href = fmt.Printf "%s#%s" .RelPermalink (anchorize $termActual) }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $msg := printf "The %q render hook was unable to find heading ID %q in %s. See %s" $renderHookName $basePath $contentPath }}
|
||||||
|
{{- if eq $errorLevel "warning" }}
|
||||||
|
{{- warnf $msg }}
|
||||||
|
{{- else if eq $errorLevel "error" }}
|
||||||
|
{{- errorf $msg }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- return (dict "href" $href) }}
|
||||||
|
{{- end -}}
|
@ -21,6 +21,9 @@ fragment, it points to an entry on the glossary page.
|
|||||||
{{- $termActual := "" }}
|
{{- $termActual := "" }}
|
||||||
{{- $termSingular := inflect.Singularize $termGiven }}
|
{{- $termSingular := inflect.Singularize $termGiven }}
|
||||||
|
|
||||||
|
{{- with $gp :=site.GetPage $basePath }}
|
||||||
|
|
||||||
|
{{- /* Validate the given term using its singular and plural forms. */}}
|
||||||
{{- if site.GetPage (urls.JoinPath $basePath $termGiven) }}
|
{{- if site.GetPage (urls.JoinPath $basePath $termGiven) }}
|
||||||
{{- $termActual = $termGiven }}
|
{{- $termActual = $termGiven }}
|
||||||
{{- else if site.GetPage (urls.JoinPath $basePath $termSingular) }}
|
{{- else if site.GetPage (urls.JoinPath $basePath $termSingular) }}
|
||||||
@ -29,14 +32,15 @@ fragment, it points to an entry on the glossary page.
|
|||||||
{{- errorf "The glossary link (%s) shortcode was unable to find a defintion for either the singular or plural form of the term %q: see %s" $.Name $termGiven $.Position }}
|
{{- errorf "The glossary link (%s) shortcode was unable to find a defintion for either the singular or plural form of the term %q: see %s" $.Name $termGiven $.Position }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Render the link. */}}
|
||||||
{{- if $termActual }}
|
{{- if $termActual }}
|
||||||
{{- with site.GetPage $basePath }}
|
{{- $href := fmt.Printf "%s#%s" $gp.RelPermalink (anchorize $termActual) }}
|
||||||
{{- $href := fmt.Printf "%s#%s" .RelPermalink (anchorize $termActual) }}
|
|
||||||
[{{ $termGiven }}]({{ $href }}){{/* Do not indent. */}}
|
[{{ $termGiven }}]({{ $href }}){{/* Do not indent. */}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
{{- else }}
|
{{- else }}
|
||||||
{{- errorf "The glossary link (%s) shortcode was unable to find %s: see %s" $.Name $basePath $.Position }}
|
{{- errorf "The glossary link (%s) shortcode was unable to find %s: see %s" $.Name $basePath $.Position }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
|
||||||
{{- else }}
|
{{- else }}
|
||||||
{{- errorf "The glossary link (%s) shortcode requires one positional parameter: see %s" $.Name $.Position }}
|
{{- errorf "The glossary link (%s) shortcode requires one positional parameter: see %s" $.Name $.Position }}
|
||||||
{{- end }}
|
{{- end -}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user