mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-17 21:01:26 +02:00
Add page fragments support to Related
The main topic of this commit is that you can now index fragments (content heading identifiers) when calling `.Related`. You can do this by: * Configure one or more indices with type `fragments` * The name of those index configurations maps to an (optional) front matter slice with fragment references. This allows you to link page<->fragment and page<->page. * This also will index all the fragments (heading identifiers) of the pages. It's also possible to use type `fragments` indices in shortcode, e.g.: ``` {{ $related := site.RegularPages.Related .Page }} ``` But, and this is important, you need to include the shortcode using the `{{<` delimiter. Not doing so will create infinite loops and timeouts. This commit also: * Adds two new methods to Page: Fragments (can also be used to build ToC) and HeadingsFiltered (this is only used in Related Content with index type `fragments` and `enableFilter` set to true. * Consolidates all `.Related*` methods into one, which takes either a `Page` or an options map as its only argument. * Add `context.Context` to all of the content related Page API. Turns out it wasn't strictly needed for this particular feature, but it will soon become usefil, e.g. in #9339. Closes #10711 Updates #9339 Updates #10725
This commit is contained in:
@@ -14,162 +14,9 @@
|
||||
package hugolib
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/htesting"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
)
|
||||
|
||||
// We have many tests for the different resize operations etc. in the resource package,
|
||||
// this is an integration test.
|
||||
func TestImageOps(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
// Make this a real as possible.
|
||||
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "image-resize")
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer clean()
|
||||
|
||||
newBuilder := func(timeout any) *sitesBuilder {
|
||||
v := config.NewWithTestDefaults()
|
||||
v.Set("workingDir", workDir)
|
||||
v.Set("baseURL", "https://example.org")
|
||||
v.Set("timeout", timeout)
|
||||
|
||||
b := newTestSitesBuilder(t).WithWorkingDir(workDir)
|
||||
b.Fs = hugofs.NewDefault(v)
|
||||
b.WithViper(v)
|
||||
b.WithContent("mybundle/index.md", `
|
||||
---
|
||||
title: "My bundle"
|
||||
---
|
||||
|
||||
{{< imgproc >}}
|
||||
|
||||
`)
|
||||
|
||||
b.WithTemplatesAdded(
|
||||
"shortcodes/imgproc.html", `
|
||||
{{ $img := resources.Get "images/sunset.jpg" }}
|
||||
{{ $r := $img.Resize "129x239" }}
|
||||
IMG SHORTCODE: {{ $r.RelPermalink }}/{{ $r.Width }}
|
||||
`,
|
||||
"index.html", `
|
||||
{{ $p := .Site.GetPage "mybundle" }}
|
||||
{{ $img1 := resources.Get "images/sunset.jpg" }}
|
||||
{{ $img2 := $p.Resources.GetMatch "sunset.jpg" }}
|
||||
{{ $img3 := resources.GetMatch "images/*.jpg" }}
|
||||
{{ $r := $img1.Resize "123x234" }}
|
||||
{{ $r2 := $r.Resize "12x23" }}
|
||||
{{ $b := $img2.Resize "345x678" }}
|
||||
{{ $b2 := $b.Resize "34x67" }}
|
||||
{{ $c := $img3.Resize "456x789" }}
|
||||
{{ $fingerprinted := $img1.Resize "350x" | fingerprint }}
|
||||
|
||||
{{ $images := slice $r $r2 $b $b2 $c $fingerprinted }}
|
||||
|
||||
{{ range $i, $r := $images }}
|
||||
{{ printf "Resized%d:" (add $i 1) }} {{ $r.Name }}|{{ $r.Width }}|{{ $r.Height }}|{{ $r.MediaType }}|{{ $r.RelPermalink }}|
|
||||
{{ end }}
|
||||
|
||||
{{ $blurryGrayscale1 := $r | images.Filter images.Grayscale (images.GaussianBlur 8) }}
|
||||
BG1: {{ $blurryGrayscale1.RelPermalink }}/{{ $blurryGrayscale1.Width }}
|
||||
{{ $blurryGrayscale2 := $r.Filter images.Grayscale (images.GaussianBlur 8) }}
|
||||
BG2: {{ $blurryGrayscale2.RelPermalink }}/{{ $blurryGrayscale2.Width }}
|
||||
{{ $blurryGrayscale2_2 := $r.Filter images.Grayscale (images.GaussianBlur 8) }}
|
||||
BG2_2: {{ $blurryGrayscale2_2.RelPermalink }}/{{ $blurryGrayscale2_2.Width }}
|
||||
|
||||
{{ $filters := slice images.Grayscale (images.GaussianBlur 9) }}
|
||||
{{ $blurryGrayscale3 := $r | images.Filter $filters }}
|
||||
BG3: {{ $blurryGrayscale3.RelPermalink }}/{{ $blurryGrayscale3.Width }}
|
||||
|
||||
{{ $blurryGrayscale4 := $r.Filter $filters }}
|
||||
BG4: {{ $blurryGrayscale4.RelPermalink }}/{{ $blurryGrayscale4.Width }}
|
||||
|
||||
{{ $p.Content }}
|
||||
|
||||
`)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
imageDir := filepath.Join(workDir, "assets", "images")
|
||||
bundleDir := filepath.Join(workDir, "content", "mybundle")
|
||||
|
||||
c.Assert(os.MkdirAll(imageDir, 0777), qt.IsNil)
|
||||
c.Assert(os.MkdirAll(bundleDir, 0777), qt.IsNil)
|
||||
src, err := os.Open("testdata/sunset.jpg")
|
||||
c.Assert(err, qt.IsNil)
|
||||
out, err := os.Create(filepath.Join(imageDir, "sunset.jpg"))
|
||||
c.Assert(err, qt.IsNil)
|
||||
_, err = io.Copy(out, src)
|
||||
c.Assert(err, qt.IsNil)
|
||||
out.Close()
|
||||
|
||||
src.Seek(0, 0)
|
||||
|
||||
out, err = os.Create(filepath.Join(bundleDir, "sunset.jpg"))
|
||||
c.Assert(err, qt.IsNil)
|
||||
_, err = io.Copy(out, src)
|
||||
c.Assert(err, qt.IsNil)
|
||||
out.Close()
|
||||
src.Close()
|
||||
|
||||
// First build it with a very short timeout to trigger errors.
|
||||
b := newBuilder("10ns")
|
||||
|
||||
imgExpect := `
|
||||
Resized1: images/sunset.jpg|123|234|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_123x234_resize_q75_box.jpg|
|
||||
Resized2: images/sunset.jpg|12|23|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ada4bb1a57f77a63306e3bd67286248e.jpg|
|
||||
Resized3: sunset.jpg|345|678|image/jpeg|/mybundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_345x678_resize_q75_box.jpg|
|
||||
Resized4: sunset.jpg|34|67|image/jpeg|/mybundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_44d8c928664d7c5a67377c6ec58425ce.jpg|
|
||||
Resized5: images/sunset.jpg|456|789|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_456x789_resize_q75_box.jpg|
|
||||
Resized6: images/sunset.jpg|350|219|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_350x0_resize_q75_box.a86fe88d894e5db613f6aa8a80538fefc25b20fa24ba0d782c057adcef616f56.jpg|
|
||||
BG1: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_2ae8bb993431ec1aec40fe59927b46b4.jpg/123
|
||||
BG2: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_2ae8bb993431ec1aec40fe59927b46b4.jpg/123
|
||||
BG3: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ed7740a90b82802261c2fbdb98bc8082.jpg/123
|
||||
BG4: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ed7740a90b82802261c2fbdb98bc8082.jpg/123
|
||||
IMG SHORTCODE: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_129x239_resize_q75_box.jpg/129
|
||||
`
|
||||
|
||||
assertImages := func() {
|
||||
b.Helper()
|
||||
b.AssertFileContent("public/index.html", imgExpect)
|
||||
b.AssertImage(350, 219, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_350x0_resize_q75_box.a86fe88d894e5db613f6aa8a80538fefc25b20fa24ba0d782c057adcef616f56.jpg")
|
||||
b.AssertImage(129, 239, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_129x239_resize_q75_box.jpg")
|
||||
}
|
||||
|
||||
err = b.BuildE(BuildCfg{})
|
||||
if runtime.GOOS != "windows" && !strings.Contains(runtime.GOARCH, "arm") && !htesting.IsGitHubAction() {
|
||||
// TODO(bep)
|
||||
c.Assert(err, qt.Not(qt.IsNil))
|
||||
}
|
||||
|
||||
b = newBuilder(29000)
|
||||
b.Build(BuildCfg{})
|
||||
|
||||
assertImages()
|
||||
|
||||
// Truncate one image.
|
||||
imgInCache := filepath.Join(workDir, "resources/_gen/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ed7740a90b82802261c2fbdb98bc8082.jpg")
|
||||
f, err := os.Create(imgInCache)
|
||||
c.Assert(err, qt.IsNil)
|
||||
f.Close()
|
||||
|
||||
// Build it again to make sure we read images from file cache.
|
||||
b = newBuilder("30s")
|
||||
b.Build(BuildCfg{})
|
||||
|
||||
assertImages()
|
||||
}
|
||||
|
||||
func TestImageResizeMultilingual(t *testing.T) {
|
||||
b := newTestSitesBuilder(t).WithConfigFile("toml", `
|
||||
baseURL="https://example.org"
|
||||
|
Reference in New Issue
Block a user