diff --git a/docs/content/introduction/quickstart/magic.gif b/docs/assets/images/magic.gif
similarity index 100%
rename from docs/content/introduction/quickstart/magic.gif
rename to docs/assets/images/magic.gif
diff --git a/docs/content/authoring/markdown.en.md b/docs/content/authoring/markdown.en.md
index e0d3aaf2fc..f3c8d490bc 100644
--- a/docs/content/authoring/markdown.en.md
+++ b/docs/content/authoring/markdown.en.md
@@ -681,6 +681,34 @@ That's some more text with a footnote.[^someid]
Blue light glows blue.
{{% /notice %}}
+### Link Effects
+
+{{% badge color="#7dc903" icon="fa-fw fas fa-puzzle-piece" %}}Relearn{{% /badge %}} This theme allows additional non-standard formatting by setting query parameter at the end of the URL. See the [link effects docs](authoring/linkeffects) for a detailed example and how to configure it.
+
+#### Target
+
+Add query parameter `target=_self` or `target=_blank` to override [site-wide settings](authoring/frontmatter/linking#opening-links) of [the target behavior](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target) individuallly for each link.
+
+````md
+[Magic in new window](images/magic.gif?target=_blank)
+````
+
+{{% notice style="code" icon="eye" title="Result" %}}
+[Magic in new window](images/magic.gif?target=_blank)
+{{% /notice %}}
+
+#### Download
+
+Add query parameter `download` or `download=myfile.gif` to force your browser [to download the link target](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download) instead of opening it.
+
+````md
+[Magic as a download](images/magic.gif?download)
+````
+
+{{% notice style="code" icon="eye" title="Result" %}}
+[Magic as a download](images/magic.gif?download)
+{{% /notice %}}
+
## Images
### Basic Images
diff --git a/docs/content/configuration/customization/imageeffects.en.md b/docs/content/configuration/customization/imageeffects.en.md
index 3f3bba39c4..8a92e0463f 100644
--- a/docs/content/configuration/customization/imageeffects.en.md
+++ b/docs/content/configuration/customization/imageeffects.en.md
@@ -56,27 +56,21 @@ With this configuration in effect, the following URL
would result in
````html {title="HTML"}
-
+
````
## Styling Effects
-If the resulting effect value is
-
-- `true`: add a class with the effect's name
-- `false`: add a class with the effect's name and a "no" prefix
+If the resulting effect value is `true` a class with the effect's name will be added.
Styles for default effects are contained in the theme. Add styles for your custom effects to `layouts/partials/content-header.html`.
-For the above example you could add styles for both boolean cases:
+For the above custom effect you could add the following style:
````html {title="layouts/partials/content-header.html"}
````
diff --git a/docs/content/introduction/quickstart/_index.en.md b/docs/content/introduction/quickstart/_index.en.md
index ca938af756..d07f827efe 100644
--- a/docs/content/introduction/quickstart/_index.en.md
+++ b/docs/content/introduction/quickstart/_index.en.md
@@ -127,7 +127,7 @@ Open [http://localhost:1313](http://localhost:1313) in your web browser.
You can keep the server running while you edit. The browser will update automatically when you save changes.
-{{% figure src="magic.gif" link="https://gohugo.io" alt="Magic" caption="It's a kind of magic" %}}
+{{% figure src="images/magic.gif" link="https://gohugo.io" alt="Magic" caption="It's a kind of magic" %}}
## Build and Deploy
diff --git a/docs/content/introduction/releasenotes/7/4.en.md b/docs/content/introduction/releasenotes/7/4.en.md
index 888ab1bdad..3cba5a2495 100644
--- a/docs/content/introduction/releasenotes/7/4.en.md
+++ b/docs/content/introduction/releasenotes/7/4.en.md
@@ -10,9 +10,24 @@ weight = -4
### New
-- {{% badge style="info" icon="plus-circle" title=" " %}}New{{% /badge %}} If [`link.errorlevel` is configured](authoring/frontmatter/linking/#enabling-link-and-image-link-warnings), now also the `pageRef` of a [Hugo menu item](https://gohugo.io/content-management/menus/) and the `menuPageRef` in a [page's front matter](configuration/sidebar/menus/#displaying-arbitrary-links-in-a-page-menu) will be checked for existence.
+- {{% badge style="info" icon="plus-circle" title=" " %}}New{{% /badge %}} The theme now allows page references (given as `pageRef` of a [Hugo menu item](https://gohugo.io/content-management/menus/), `pageRef` parameter of a [`sidebarmenus` entry ](configuration/sidebar/menus#defining-sidebar-menus) and the `menuPageRef` in a [page's front matter](configuration/sidebar/menus/#displaying-arbitrary-links-in-a-page-menu)) to also be global resources from your `assets` directory.
-- {{% badge style="info" icon="plus-circle" title=" " %}}New{{% /badge %}} You can now [configure an ignore list](authoring/frontmatter/linking/#ignoring-false-negatives) of addresses that should be ignored if an errorlevel test fails. This is configured by setting `errorignore=[]` in your `hugo.toml`. This helps to remove false negatives from the output while still benefitting from the check for all other addresses.
+- {{% badge style="info" icon="plus-circle" title=" " %}}New{{% /badge %}} If [`link.errorlevel` is configured](authoring/frontmatter/linking/#enabling-link-and-image-link-warnings), now also page references will be checked for existence.
+
+- {{% badge style="info" icon="plus-circle" title=" " %}}New{{% /badge %}} It is now possible to add query parameter and an optional fragment part to all links. This is regardless whether it is a local or remote address and also applies to Hugo's internal path.
+
+ By that you can now use it on Markdown links, image links, page references.
+
+- {{% badge style="info" icon="plus-circle" title=" " %}}New{{% /badge %}} This release introduces [link effects](authoring/markdown#link-effects) which work similar to [image effects](authoring/markdown#image-effects) and can be set as query parameter on any link.
+
+ With that you currently can specify
+
+ - a link target individually for each link
+ - that a link should result in a file download in your browser
+
+- {{% badge style="info" icon="plus-circle" title=" " %}}New{{% /badge %}} You can now [configure an ignore list](authoring/frontmatter/linking/#ignoring-false-negatives) of addresses that should be ignored if an errorlevel test fails. This is configured by setting `errorignore=[]` globally in your `hugo.toml` for all errorlevel checks.
+
+ This helps to remove false negatives while still benefitting from the check for all other addresses.
- {{% badge style="info" icon="plus-circle" title=" " %}}New{{% /badge %}} The theme supports the new [`source` output format](configuration/sitemanagement/outputformats/#source-support) which behaves similar in configuration as the `markdown` output format but allows the original Markdown source including the front matter of a page to be viewed.
diff --git a/layouts/partials/_relearn/imageAttributes.gotmpl b/layouts/partials/_relearn/imageAttributes.gotmpl
new file mode 100644
index 0000000000..6ad73f485e
--- /dev/null
+++ b/layouts/partials/_relearn/imageAttributes.gotmpl
@@ -0,0 +1,71 @@
+{{- $attributes := dict }}
+{{- $height := "auto" }}
+{{- $width := "auto" }}
+{{- $effects := dict "border" false "lazy" true "lightbox" true "shadow" false }}
+{{- if .page.Site.Params.imageeffects }}
+ {{- $effects = merge $effects .page.Site.Params.imageeffects }}
+{{- end }}
+{{- if .page.Params.imageEffects }}
+ {{- $effects = merge $effects .page.Params.imageEffects }}
+{{- end }}
+{{- $u := urls.Parse .url }}
+{{- if $u.RawQuery }}
+ {{- if $u.Query.Has "classes" }}
+ {{- $classes := slice | append (split ($u.Query.Get "classes") ",") }}
+ {{- range $classes }}
+ {{- $k := . }}
+ {{- $v := true }}
+ {{- if strings.HasPrefix $k "no" }}
+ {{- $k := strings.TrimPrefix "no" $k }}
+ {{- $v := false }}
+ {{- end }}
+ {{- $effects = merge $effects (dict $k $v) }}
+ {{- end }}
+ {{- end }}
+ {{- if $u.Query.Has "featherlight" }}
+ {{- $filepath := "[virtual file]" }}{{ with and .page .page.File .page.File.Filename }}{{ $filepath = . }}{{ end }}
+ {{- warnf "%q: DEPRECATED usage of 'featherlight' image CSS class found, use 'lightbox' instead; see https://mcshelby.github.io/hugo-theme-relearn/introduction/releasenotes/5/#5-11-0" $filepath }}
+ {{- $effects = merge $effects (dict "lightbox" (ne ($u.Query.Get "featherlight") "false")) }}
+ {{- end }}
+ {{- range $k, $v := $effects }}
+ {{- if $u.Query.Has $k }}
+ {{- $effects = merge $effects (dict $k (ne ($u.Query.Get $k) "false")) }}
+ {{- end }}
+ {{- end }}
+ {{- range $k, $v := $effects }}
+ {{- if $u.Query.Has $k }}
+ {{- $paramValue := $u.Query.Get $k }}
+ {{- $newValue := true }}
+ {{- if eq $paramValue "" }}
+ {{- $newValue = true }}
+ {{- else if eq $paramValue "true" }}
+ {{- $newValue = true }}
+ {{- else if eq $paramValue "false" }}
+ {{- $newValue = false }}
+ {{- else }}
+ {{- $newValue = $paramValue }}
+ {{- end }}
+ {{- $effects = merge $effects (dict $k $newValue) }}
+ {{- end }}
+ {{- end }}
+ {{- with $u.Query.Get "height" }}
+ {{- $height = . }}
+ {{- end }}
+ {{- with $u.Query.Get "width" }}
+ {{- $width = . }}
+ {{- end }}
+{{- end }}
+{{- $classes := slice }}
+{{- range $k, $v := $effects }}
+ {{- if $v }}
+ {{- if eq (printf "%T" $v) "bool" }}
+ {{- $classes = $classes | append $k }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+{{- if $attributes.class }}{{ $classes = $classes | append $attributes.class }}{{ end }}
+{{- $attributes = merge $attributes (dict "class" (delimit $classes " ")) }}
+{{- $attributes = merge $attributes (dict "src" .url) }}
+{{- $attributes = merge $attributes (dict "style" (printf " height: %s; width: %s;%s" $height $width (index $attributes "style" | default ""))) }}
+{{- if $effects.lazy }}{{ $attributes = merge $attributes (dict "loading" "lazy") }}{{ end }}
+{{- return $attributes }}
\ No newline at end of file
diff --git a/layouts/partials/_relearn/linkAttributes.gotmpl b/layouts/partials/_relearn/linkAttributes.gotmpl
new file mode 100644
index 0000000000..6827516620
--- /dev/null
+++ b/layouts/partials/_relearn/linkAttributes.gotmpl
@@ -0,0 +1,72 @@
+{{- $attributes := dict }}
+{{- /* target will be boolean false if no user defined value was set and effect default should be applied */}}
+{{- $target := false }}
+{{- $u := urls.Parse .url }}
+{{- if $u.IsAbs }}
+ {{- $attributes = merge $attributes (dict "rel" "external") }}
+ {{- $target = "_blank" }}
+ {{- if isset .page.Site.Params "externallinktarget" }}
+ {{- $target = .page.Site.Params.externalLinkTarget }}
+ {{- if in (slice "false" false 0) $target }}
+ {{- $target = "" }}
+ {{- end }}
+ {{- if in (slice "true" true 1) $target }}
+ {{- $target = "_blank" }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+{{- $effects := dict "download" false "target" false }}
+{{- if .page.Site.Params.linkeffects }}
+ {{- $effects = merge $effects .page.Site.Params.linkeffects }}
+{{- end }}
+{{- if .page.Params.linkeffects }}
+ {{- $effects = merge $effects .page.Params.linkeffects }}
+{{- end }}
+{{- $target := .target | default $target }}
+{{- if ne (printf "%T" $target) "bool" }}
+ {{- $effects = merge $effects (dict "target" $target) }}
+{{- end }}
+{{- if $u.RawQuery }}
+ {{- if $u.Query.Has "classes" }}
+ {{- $classes := slice | append (split ($u.Query.Get "classes") ",") }}
+ {{- range $classes }}
+ {{- $k := . }}
+ {{- $v := true }}
+ {{- if strings.HasPrefix $k "no" }}
+ {{- $k := strings.TrimPrefix "no" $k }}
+ {{- $v := false }}
+ {{- end }}
+ {{- $effects = merge $effects (dict $k $v) }}
+ {{- end }}
+ {{- end }}
+ {{- range $k, $v := $effects }}
+ {{- if $u.Query.Has $k }}
+ {{- $paramValue := $u.Query.Get $k }}
+ {{- $newValue := true }}
+ {{- if eq $paramValue "" }}
+ {{- $newValue = true }}
+ {{- else if eq $paramValue "true" }}
+ {{- $newValue = true }}
+ {{- else if eq $paramValue "false" }}
+ {{- $newValue = false }}
+ {{- else }}
+ {{- $newValue = $paramValue }}
+ {{- end }}
+ {{- $effects = merge $effects (dict $k $newValue) }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+{{- $classes := slice }}
+{{- range $k, $v := $effects }}
+ {{- if $v }}
+ {{- if eq (printf "%T" $v) "bool" }}
+ {{- $classes = $classes | append $k }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+{{- if $attributes.class }}{{ $classes = $classes | append $attributes.class }}{{ end }}
+{{- $attributes = merge $attributes (dict "class" (delimit $classes " ")) }}
+{{- $attributes = merge $attributes (dict "href" .url) }}
+{{- $attributes = merge $attributes (dict "download" $effects.download) }}
+{{- $attributes = merge $attributes (dict "target" $effects.target) }}
+{{- return $attributes }}
\ No newline at end of file
diff --git a/layouts/partials/shortcodes/image.html b/layouts/partials/shortcodes/image.html
index a147731996..3ca43f9c43 100644
--- a/layouts/partials/shortcodes/image.html
+++ b/layouts/partials/shortcodes/image.html
@@ -7,98 +7,56 @@
{{- end }}
{{- $title := .title }}
{{- $alt := .alt }}
-{{- $effects := dict "border" false "lazy" true "lightbox" true "shadow" false }}
-{{- if $page.Site.Params.imageeffects }}
- {{- $effects = merge $effects $page.Site.Params.imageeffects }}
-{{- end }}
-{{- if $page.Params.imageEffects }}
- {{- $effects = merge $effects $page.Params.imageEffects }}
-{{- end }}
-{{- $height := "auto" }}
-{{- $width := "auto" }}
{{- $attributes := .attributes | default dict }}
{{- $u := urls.Parse .url }}
{{- $src := $u.String }}
{{- if $u.IsAbs }}
{{- partialCached "_relearn/urlExists.gotmpl" (dict "url" .url "page" $page "type" "image") $u.String }}
{{- else }}
- {{- $path := strings.TrimPrefix "./" $u.Path }}
- {{- with or
- ($page.Resources.Get $path)
- (resources.Get $path)
- }}
- {{- $src = .RelPermalink }}
- {{- with $u.RawQuery }}
- {{- $src = printf "%s?%s" $src . }}
- {{- end }}
- {{- with $u.Fragment }}
- {{- $src = printf "%s#%s" $src . }}
- {{- end }}
+ {{- $linkObject := partial "_relearn/linkObject.gotmpl" (dict "url" .url "page" $page "searchPage" false) }}
+ {{- if $linkObject }}
+ {{- $src = partial "_relearn/decoratedLink.gotmpl" (dict "url" .url "page" $page "linkObject" $linkObject "param" "image") }}
{{- else }}
{{- $filepath := "[virtual file]" }}{{ with and $page $page.File $page.File.Filename }}{{ $filepath = . }}{{ end }}
{{- $msg := printf "%q: image '%s' is not a resource" $filepath .url }}
{{- partial "_relearn/urlErrorReport.gotmpl" (dict "url" .url "page" $page "param" "image" "msg" $msg) }}
{{- end }}
{{- end }}
-{{- if $u.RawQuery }}
- {{- if $u.Query.Has "classes" }}
- {{- $classes := slice | append (split ($u.Query.Get "classes") ",") }}
- {{- range $classes }}
- {{- $k := . }}
- {{- $v := true }}
- {{- if strings.HasPrefix $k "no" }}
- {{- $k := strings.TrimPrefix "no" $k }}
- {{- $v := false }}
- {{- end }}
- {{- $effects = merge $effects (dict $k $v) }}
- {{- end }}
- {{- end }}
- {{- if $u.Query.Has "featherlight" }}
- {{- $filepath := "[virtual file]" }}{{ with and $page $page.File $page.File.Filename }}{{ $filepath = . }}{{ end }}
- {{- warnf "%q: DEPRECATED usage of 'featherlight' image CSS class found, use 'lightbox' instead; see https://mcshelby.github.io/hugo-theme-relearn/introduction/releasenotes/5/#5-11-0" $filepath }}
- {{- $effects = merge $effects (dict "lightbox" (ne ($u.Query.Get "featherlight") "false")) }}
- {{- end }}
- {{- range $k, $v := $effects }}
- {{- if $u.Query.Has $k }}
- {{- $effects = merge $effects (dict $k (ne ($u.Query.Get $k) "false")) }}
- {{- end }}
- {{- end }}
- {{- with $u.Query.Get "height" }}
- {{- $height = . }}
- {{- end }}
- {{- with $u.Query.Get "width" }}
- {{- $width = . }}
- {{- end }}
-{{- end }}
-{{- $classes := slice }}
-{{- range $k, $v := $effects }}
- {{- $c := printf "%s%s" (cond $v "" "no") $k }}
- {{- $classes = $classes | append $c }}
-{{- end }}
{{- $id := cond (or (eq .id nil) (eq .id "")) (partial "_relearn/makeRandomMd5.gotmpl" $page) .id }}
-{{- $attributes = merge $attributes (dict "alt" $alt "src" $src "title" ($title | transform.HTMLEscape)) }}
-{{- if $effects.lazy }}
- {{- $attributes = merge $attributes (dict "loading" "lazy") }}
-{{- end }}
-{{- if $effects.lightbox -}}
+{{- $attributes = merge $attributes (partial "_relearn/imageAttributes.gotmpl" (dict "url" $src "page" $page)) }}
+{{- $attributes = merge $attributes (dict "alt" $alt "title" ($title | transform.HTMLEscape)) }}
+{{- $classes := split $attributes.class " " }}
+{{- $isLightbox := in $classes "lightbox" }}
+{{- if $isLightbox -}}
{{- end }}
-{{- $attributes_figure := merge $attributes (dict "class" (delimit (append (index $attributes "class" | default slice) "figure-image" $classes) " ")) }}
-{{- $attributes_figure = merge $attributes_figure (dict "style" (delimit (slice (index $attributes "style") (printf "height: %s; width: %s;" $height $width)) " ")) -}}
+{{- $attributes_figure := $attributes }}
+{{- $attributes_figure = merge $attributes_figure (dict "class" (delimit ((split $attributes_figure.class " ") | append "figure-image") " ")) }}
+{{- $attributes_figure = merge $attributes_figure (dict "style" (index $attributes_figure "style")) -}}
-{{- if $effects.lightbox -}}
+{{- if $isLightbox -}}
-{{- $attributes_lightbox := merge $attributes (dict "class" (delimit (append (index $attributes "class" | default slice) "lightbox-image" $classes) " ")) -}}
+{{- $attributes_lightbox := $attributes }}
+{{- $attributes_lightbox = merge $attributes_lightbox (dict "class" (delimit ((split $attributes_lightbox.class " ") | append "lightbox-image") " ")) }}
+{{- $attributes_lightbox = merge $attributes_lightbox (dict "style" "") -}}
{{- end }}
\ No newline at end of file
diff --git a/layouts/partials/shortcodes/link.html b/layouts/partials/shortcodes/link.html
index 8c542bb7aa..e2a40b2ef4 100644
--- a/layouts/partials/shortcodes/link.html
+++ b/layouts/partials/shortcodes/link.html
@@ -12,33 +12,32 @@
{{- $attributes := .attributes | default dict }}
{{- $title := .title | default "" }}
{{- $title = trim $title " " }}
-{{- $attributes = $attributes | merge (dict "title" ($title | transform.HTMLEscape)) }}
+{{- $attributes = merge $attributes (dict "title" ($title | transform.HTMLEscape)) }}
{{- $content := .content }}
-{{- $target := .target | default "" }}
+{{- /* target will be boolean false if no user defined value was set and effect default should be applied */}}
+{{- $target := false }}
{{- $u := urls.Parse .url }}
{{- $href := $u.String }}
{{- if $u.IsAbs }}
{{- partialCached "_relearn/urlExists.gotmpl" (dict "url" .url "page" $page "type" "link") $u.String }}
- {{- $attributes = merge $attributes (dict "rel" "external") }}
- {{- $target = "_blank" }}
- {{- if isset $page.Site.Params "externallinktarget" }}
- {{- $target = $page.Site.Params.externalLinkTarget }}
- {{- end }}
- {{- $attributes = $attributes | merge (dict "target" $target) }}
{{- else }}
- {{- $linkObject := partial "_relearn/linkObject.gotmpl" (dict "url" $.url "page" $page) }}
- {{- with $linkObject }}
- {{- $href = partial "_relearn/decoratedLink.gotmpl" (dict "url" $.url "page" $page "linkObject" . "param" "link") }}
+ {{- $linkObject := partial "_relearn/linkObject.gotmpl" (dict "url" .url "page" $page) }}
+ {{- if $linkObject }}
+ {{- $href = partial "_relearn/decoratedLink.gotmpl" (dict "url" .url "page" $page "linkObject" $linkObject "param" "link") }}
{{- else }}
{{- $filepath := "[virtual file]" }}{{ with and $page $page.File $page.File.Filename }}{{ $filepath = . }}{{ end }}
{{- $msg := printf "%q: link '%s' is not a page or a resource" $filepath .url }}
{{- partial "_relearn/urlErrorReport.gotmpl" (dict "url" .url "page" $page "param" "link" "msg" $msg) }}
{{- end }}
{{- end }}
-{{- $attributes = $attributes | merge (dict "href" $href) -}}
+{{- $attributes = merge $attributes (partial "_relearn/linkAttributes.gotmpl" (dict "url" $href "page" $page "target" .target)) -}}
{{ $content | safeHTML }}
\ No newline at end of file
diff --git a/layouts/partials/version.txt b/layouts/partials/version.txt
index 7f2320e745..e5f82aff30 100644
--- a/layouts/partials/version.txt
+++ b/layouts/partials/version.txt
@@ -1 +1 @@
-7.3.2+14c19bb13cecd2d3e72f5f53ad2b03f71dfcef81
\ No newline at end of file
+7.3.2+516e552ecefcdf2f67cb0c34869f225affe45f73
\ No newline at end of file