resource/page: Add Page.Ancestors

Fixes #10567
This commit is contained in:
Septs 2022-11-30 12:02:57 +08:00 committed by Bjørn Erik Pedersen
parent 7874b96815
commit 3a216186b2
7 changed files with 38 additions and 12 deletions

View file

@ -63,19 +63,16 @@ If you need a specific template for a sub-section, you need to adjust either the
With the available [section variables and methods](#section-page-variables-and-methods) you can build powerful navigation. One common example would be a partial to show Breadcrumb navigation: With the available [section variables and methods](#section-page-variables-and-methods) you can build powerful navigation. One common example would be a partial to show Breadcrumb navigation:
{{< code file="layouts/partials/breadcrumb.html" download="breadcrumb.html" >}} {{< code file="layouts/partials/breadcrumb.html" download="breadcrumb.html" >}}
<ol class="nav navbar-nav"> <ol class="nav navbar-nav">
{{ template "breadcrumbnav" (dict "p1" . "p2" .) }} <ul>
</ol> {{- range .Ancestors.Reverse }}
{{ define "breadcrumbnav" }} <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ if .p1.Parent }} {{- end }}
{{ template "breadcrumbnav" (dict "p1" .p1.Parent "p2" .p2 ) }} <li class="active" aria-current="page">
{{ else if not .p1.IsHome }} <a href="{{ .Permalink }}">{{ .Title }}</a>
{{ template "breadcrumbnav" (dict "p1" .p1.Site.Home "p2" .p2 ) }}
{{ end }}
<li{{ if eq .p1 .p2 }} class="active" aria-current="page" {{ end }}>
<a href="{{ .p1.Permalink }}">{{ .p1.Title }}</a>
</li> </li>
{{ end }} </ul>
</ol>
{{< /code >}} {{< /code >}}
## Section Page Variables and Methods ## Section Page Variables and Methods

View file

@ -32,6 +32,9 @@ See [`.Scratch`](/functions/scratch/) for page-scoped, writable variables.
.Aliases .Aliases
: aliases of this page : aliases of this page
.Ancestors
: get the ancestors of each page, simplify [breadcrumb navigation]({{< relref "content-management/sections#example-breadcrumb-navigation" >}}) implementation complexity
.BundleType .BundleType
: the [bundle] type: `leaf`, `branch`, or an empty string if the page is not a bundle. : the [bundle] type: `leaf`, `branch`, or an empty string if the page is not a bundle.

View file

@ -178,6 +178,15 @@ func (pt pageTree) Parent() page.Page {
return b.p return b.p
} }
func (pt pageTree) Ancestors() (parents page.Pages) {
parent := pt.Parent()
for parent != nil {
parents = append(parents, parent)
parent = parent.Parent()
}
return
}
func (pt pageTree) Sections() page.Pages { func (pt pageTree) Sections() page.Pages {
if pt.p.bucket == nil { if pt.p.bucket == nil {
return nil return nil

View file

@ -181,12 +181,14 @@ PAG|{{ .Title }}|{{ $sect.InSection . }}
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
c.Assert(active, qt.Equals, true) c.Assert(active, qt.Equals, true)
c.Assert(p.FirstSection(), qt.Equals, p) c.Assert(p.FirstSection(), qt.Equals, p)
c.Assert(len(p.Ancestors()), qt.Equals, 1)
}}, }},
{"l1", func(c *qt.C, p page.Page) { {"l1", func(c *qt.C, p page.Page) {
c.Assert(p.Title(), qt.Equals, "L1s") c.Assert(p.Title(), qt.Equals, "L1s")
c.Assert(len(p.Pages()), qt.Equals, 4) // 2 pages + 2 sections c.Assert(len(p.Pages()), qt.Equals, 4) // 2 pages + 2 sections
c.Assert(p.Parent().IsHome(), qt.Equals, true) c.Assert(p.Parent().IsHome(), qt.Equals, true)
c.Assert(len(p.Sections()), qt.Equals, 2) c.Assert(len(p.Sections()), qt.Equals, 2)
c.Assert(len(p.Ancestors()), qt.Equals, 1)
}}, }},
{"l1,l2", func(c *qt.C, p page.Page) { {"l1,l2", func(c *qt.C, p page.Page) {
c.Assert(p.Title(), qt.Equals, "T2_-1") c.Assert(p.Title(), qt.Equals, "T2_-1")
@ -195,6 +197,7 @@ PAG|{{ .Title }}|{{ $sect.InSection . }}
c.Assert(p.Parent().Title(), qt.Equals, "L1s") c.Assert(p.Parent().Title(), qt.Equals, "L1s")
c.Assert(p.RelPermalink(), qt.Equals, "/l1/l2/") c.Assert(p.RelPermalink(), qt.Equals, "/l1/l2/")
c.Assert(len(p.Sections()), qt.Equals, 1) c.Assert(len(p.Sections()), qt.Equals, 1)
c.Assert(len(p.Ancestors()), qt.Equals, 2)
for _, child := range p.Pages() { for _, child := range p.Pages() {
if child.IsSection() { if child.IsSection() {
@ -237,6 +240,7 @@ PAG|{{ .Title }}|{{ $sect.InSection . }}
c.Assert(p.Pages()[0].File().Path(), qt.Equals, filepath.FromSlash("l1/l2_2/page_2_2_1.md")) c.Assert(p.Pages()[0].File().Path(), qt.Equals, filepath.FromSlash("l1/l2_2/page_2_2_1.md"))
c.Assert(p.Parent().Title(), qt.Equals, "L1s") c.Assert(p.Parent().Title(), qt.Equals, "L1s")
c.Assert(len(p.Sections()), qt.Equals, 0) c.Assert(len(p.Sections()), qt.Equals, 0)
c.Assert(len(p.Ancestors()), qt.Equals, 2)
}}, }},
{"l1,l2,l3", func(c *qt.C, p page.Page) { {"l1,l2,l3", func(c *qt.C, p page.Page) {
nilp, _ := p.GetPage("this/does/not/exist") nilp, _ := p.GetPage("this/does/not/exist")
@ -245,6 +249,7 @@ PAG|{{ .Title }}|{{ $sect.InSection . }}
c.Assert(len(p.Pages()), qt.Equals, 2) c.Assert(len(p.Pages()), qt.Equals, 2)
c.Assert(p.Parent().Title(), qt.Equals, "T2_-1") c.Assert(p.Parent().Title(), qt.Equals, "T2_-1")
c.Assert(len(p.Sections()), qt.Equals, 0) c.Assert(len(p.Sections()), qt.Equals, 0)
c.Assert(len(p.Ancestors()), qt.Equals, 3)
l1 := getPage(p, "/l1") l1 := getPage(p, "/l1")
isDescendant, err := l1.IsDescendant(p) isDescendant, err := l1.IsDescendant(p)
@ -307,6 +312,7 @@ PAG|{{ .Title }}|{{ $sect.InSection . }}
} }
c.Assert(home, qt.Not(qt.IsNil)) c.Assert(home, qt.Not(qt.IsNil))
c.Assert(len(home.Ancestors()), qt.Equals, 0)
c.Assert(len(home.Sections()), qt.Equals, 9) c.Assert(len(home.Sections()), qt.Equals, 9)
c.Assert(s.Info.Sections(), deepEqualsPages, home.Sections()) c.Assert(s.Info.Sections(), deepEqualsPages, home.Sections())

View file

@ -407,6 +407,9 @@ type TreeProvider interface {
// To get a section's subsections, see Page's Sections method. // To get a section's subsections, see Page's Sections method.
Parent() Page Parent() Page
// Ancestors returns the ancestors of each page
Ancestors() Pages
// Sections returns this section's subsections, if any. // Sections returns this section's subsections, if any.
// Note that for non-sections, this method will always return an empty list. // Note that for non-sections, this method will always return an empty list.
Sections() Pages Sections() Pages

View file

@ -348,6 +348,10 @@ func (p *nopPage) Parent() Page {
return nil return nil
} }
func (p *nopPage) Ancestors() Pages {
return nil
}
func (p *nopPage) Path() string { func (p *nopPage) Path() string {
return "" return ""
} }

View file

@ -416,6 +416,10 @@ func (p *testPage) Parent() Page {
panic("not implemented") panic("not implemented")
} }
func (p *testPage) Ancestors() Pages {
panic("not implemented")
}
func (p *testPage) Path() string { func (p *testPage) Path() string {
return p.path return p.path
} }