mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
634481ba8c
commit
d831d2fce8
7 changed files with 151 additions and 34 deletions
|
@ -24,4 +24,6 @@ aliases: []
|
||||||
returns `true` if the PAGE is the same object as the `.Page` in one of the
|
returns `true` if the PAGE is the same object as the `.Page` in one of the
|
||||||
**children menu entries** under MENUENTRY in a given MENU.
|
**children menu entries** under MENUENTRY in a given MENU.
|
||||||
|
|
||||||
|
{{< new-in "0.86.0" >}} If MENUENTRY's `.Page` is a [section](/content-management/sections/) then, from Hugo `0.86.0`, this method also returns true for any descendant of that section..
|
||||||
|
|
||||||
You can find its example use in [menu templates](/templates/menu-templates/).
|
You can find its example use in [menu templates](/templates/menu-templates/).
|
||||||
|
|
|
@ -40,6 +40,9 @@ Reference to the [page object][page-object] associated with the menu entry. This
|
||||||
will be non-nil if the menu entry is set via a page's front-matter and not via
|
will be non-nil if the menu entry is set via a page's front-matter and not via
|
||||||
the site config.
|
the site config.
|
||||||
|
|
||||||
|
.PageRef {{< new-in "0.86.0" >}}
|
||||||
|
: _string_ <br /> Can be set if defined in site config and the menu entry refers to a Page. [site.GetPage](/functions/getpage/) will be used to do the page lookup. If this is set, you don't need to set the `URL`.
|
||||||
|
|
||||||
.Name
|
.Name
|
||||||
: _string_ <br />
|
: _string_ <br />
|
||||||
Name of the menu entry. The `name` key, if set for the menu entry, sets
|
Name of the menu entry. The `name` key, if set for the menu entry, sets
|
||||||
|
|
|
@ -33,7 +33,7 @@ menu:
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSectionPagesMenu(t *testing.T) {
|
func TestMenusSectionPagesMenu(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
siteConfig := `
|
siteConfig := `
|
||||||
|
@ -106,7 +106,7 @@ Menu Main: {{ partial "menu.html" (dict "page" . "menu" "main") }}`,
|
||||||
}
|
}
|
||||||
|
|
||||||
// related issue #7594
|
// related issue #7594
|
||||||
func TestMenuSort(t *testing.T) {
|
func TestMenusSort(t *testing.T) {
|
||||||
b := newTestSitesBuilder(t).WithSimpleConfigFile()
|
b := newTestSitesBuilder(t).WithSimpleConfigFile()
|
||||||
|
|
||||||
b.WithTemplatesAdded("index.html", `
|
b.WithTemplatesAdded("index.html", `
|
||||||
|
@ -193,7 +193,7 @@ menu:
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMenuFrontMatter(t *testing.T) {
|
func TestMenusFrontMatter(t *testing.T) {
|
||||||
b := newTestSitesBuilder(t).WithSimpleConfigFile()
|
b := newTestSitesBuilder(t).WithSimpleConfigFile()
|
||||||
|
|
||||||
b.WithTemplatesAdded("index.html", `
|
b.WithTemplatesAdded("index.html", `
|
||||||
|
@ -243,7 +243,7 @@ menu:
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/gohugoio/hugo/issues/5849
|
// https://github.com/gohugoio/hugo/issues/5849
|
||||||
func TestMenuPageMultipleOutputFormats(t *testing.T) {
|
func TestMenusPageMultipleOutputFormats(t *testing.T) {
|
||||||
config := `
|
config := `
|
||||||
baseURL = "https://example.com"
|
baseURL = "https://example.com"
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ menu: "main"
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/gohugoio/hugo/issues/5989
|
// https://github.com/gohugoio/hugo/issues/5989
|
||||||
func TestMenuPageSortByDate(t *testing.T) {
|
func TestMenusPageSortByDate(t *testing.T) {
|
||||||
b := newTestSitesBuilder(t).WithSimpleConfigFile()
|
b := newTestSitesBuilder(t).WithSimpleConfigFile()
|
||||||
|
|
||||||
b.WithContent("blog/a.md", `
|
b.WithContent("blog/a.md", `
|
||||||
|
@ -399,3 +399,109 @@ key2: key2_config
|
||||||
camelCase: camelCase_config
|
camelCase: camelCase_config
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMenusShadowMembers(t *testing.T) {
|
||||||
|
b := newTestSitesBuilder(t).WithConfigFile("toml", `
|
||||||
|
[[menus.main]]
|
||||||
|
identifier = "contact"
|
||||||
|
pageRef = "contact"
|
||||||
|
title = "Contact Us"
|
||||||
|
url = "mailto:noreply@example.com"
|
||||||
|
weight = 1
|
||||||
|
[[menus.main]]
|
||||||
|
pageRef = "/blog/post3"
|
||||||
|
title = "My Post 3"
|
||||||
|
url = "/blog/post3"
|
||||||
|
|
||||||
|
`)
|
||||||
|
|
||||||
|
commonTempl := `
|
||||||
|
Main: {{ len .Site.Menus.main }}
|
||||||
|
{{ range .Site.Menus.main }}
|
||||||
|
{{ .Title }}|HasMenuCurrent: {{ $.HasMenuCurrent "main" . }}|Page: {{ .Page }}
|
||||||
|
{{ .Title }}|IsMenuCurrent: {{ $.IsMenuCurrent "main" . }}|Page: {{ .Page }}
|
||||||
|
{{ end }}
|
||||||
|
`
|
||||||
|
|
||||||
|
b.WithTemplatesAdded("index.html", commonTempl)
|
||||||
|
b.WithTemplatesAdded("_default/single.html", commonTempl)
|
||||||
|
|
||||||
|
b.WithContent("_index.md", `
|
||||||
|
---
|
||||||
|
title: "Home"
|
||||||
|
menu:
|
||||||
|
main:
|
||||||
|
weight: 10
|
||||||
|
---
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.WithContent("blog/_index.md", `
|
||||||
|
---
|
||||||
|
title: "Blog"
|
||||||
|
menu:
|
||||||
|
main:
|
||||||
|
weight: 20
|
||||||
|
---
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.WithContent("blog/post1.md", `
|
||||||
|
---
|
||||||
|
title: "My Post 1: With No Menu Defined"
|
||||||
|
---
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.WithContent("blog/post2.md", `
|
||||||
|
---
|
||||||
|
title: "My Post 2: With Menu Defined"
|
||||||
|
menu:
|
||||||
|
main:
|
||||||
|
weight: 30
|
||||||
|
---
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.WithContent("blog/post3.md", `
|
||||||
|
---
|
||||||
|
title: "My Post 2: With No Menu Defined"
|
||||||
|
---
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.WithContent("contact.md", `
|
||||||
|
---
|
||||||
|
title: "Contact: With No Menu Defined"
|
||||||
|
---
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.Build(BuildCfg{})
|
||||||
|
|
||||||
|
b.AssertFileContent("public/index.html", `
|
||||||
|
Main: 5
|
||||||
|
Home|HasMenuCurrent: false|Page: Page(/_index.md)
|
||||||
|
Blog|HasMenuCurrent: false|Page: Page(/blog/_index.md)
|
||||||
|
My Post 2: With Menu Defined|HasMenuCurrent: false|Page: Page(/blog/post2.md)
|
||||||
|
My Post 3|HasMenuCurrent: false|Page: Page(/blog/post3.md)
|
||||||
|
Contact Us|HasMenuCurrent: false|Page: Page(/contact.md)
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/blog/post1/index.html", `
|
||||||
|
Home|HasMenuCurrent: false|Page: Page(/_index.md)
|
||||||
|
Blog|HasMenuCurrent: true|Page: Page(/blog/_index.md)
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/blog/post2/index.html", `
|
||||||
|
Home|HasMenuCurrent: false|Page: Page(/_index.md)
|
||||||
|
Blog|HasMenuCurrent: true|Page: Page(/blog/_index.md)
|
||||||
|
Blog|IsMenuCurrent: false|Page: Page(/blog/_index.md)
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/blog/post3/index.html", `
|
||||||
|
Home|HasMenuCurrent: false|Page: Page(/_index.md)
|
||||||
|
Blog|HasMenuCurrent: true|Page: Page(/blog/_index.md)
|
||||||
|
`)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/contact/index.html", `
|
||||||
|
Contact Us|HasMenuCurrent: false|Page: Page(/contact.md)
|
||||||
|
Contact Us|IsMenuCurrent: true|Page: Page(/contact.md)
|
||||||
|
Blog|HasMenuCurrent: false|Page: Page(/blog/_index.md)
|
||||||
|
Blog|IsMenuCurrent: false|Page: Page(/blog/_index.md)
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
|
@ -56,7 +56,6 @@ func (p *pageMenus) menus() navigation.PageMenus {
|
||||||
func (p *pageMenus) init() {
|
func (p *pageMenus) init() {
|
||||||
p.pmInit.Do(func() {
|
p.pmInit.Do(func() {
|
||||||
p.q = navigation.NewMenuQueryProvider(
|
p.q = navigation.NewMenuQueryProvider(
|
||||||
p.p.s.Info.sectionPagesMenu,
|
|
||||||
p,
|
p,
|
||||||
p.p.s,
|
p.p.s,
|
||||||
p.p,
|
p.p,
|
||||||
|
|
|
@ -1452,6 +1452,10 @@ func (s *Site) assembleMenus() {
|
||||||
menuConfig := s.getMenusFromConfig()
|
menuConfig := s.getMenusFromConfig()
|
||||||
for name, menu := range menuConfig {
|
for name, menu := range menuConfig {
|
||||||
for _, me := range menu {
|
for _, me := range menu {
|
||||||
|
if types.IsNil(me.Page) && me.PageRef != "" {
|
||||||
|
// Try to resolve the page.
|
||||||
|
me.Page, _ = s.getPageNew(nil, me.PageRef)
|
||||||
|
}
|
||||||
flat[twoD{name, me.KeyName()}] = me
|
flat[twoD{name, me.KeyName()}] = me
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ var smc = newMenuCache()
|
||||||
type MenuEntry struct {
|
type MenuEntry struct {
|
||||||
ConfiguredURL string // The URL value from front matter / config.
|
ConfiguredURL string // The URL value from front matter / config.
|
||||||
Page Page
|
Page Page
|
||||||
|
PageRef string // The path to the page, only relevant for site config.
|
||||||
Name string
|
Name string
|
||||||
Menu string
|
Menu string
|
||||||
Identifier string
|
Identifier string
|
||||||
|
@ -63,6 +64,8 @@ type Page interface {
|
||||||
Section() string
|
Section() string
|
||||||
Weight() int
|
Weight() int
|
||||||
IsPage() bool
|
IsPage() bool
|
||||||
|
IsSection() bool
|
||||||
|
IsAncestor(other interface{}) (bool, error)
|
||||||
Params() maps.Params
|
Params() maps.Params
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,16 +109,28 @@ func (m *MenuEntry) IsEqual(inme *MenuEntry) bool {
|
||||||
// IsSameResource returns whether the two menu entries points to the same
|
// IsSameResource returns whether the two menu entries points to the same
|
||||||
// resource (URL).
|
// resource (URL).
|
||||||
func (m *MenuEntry) IsSameResource(inme *MenuEntry) bool {
|
func (m *MenuEntry) IsSameResource(inme *MenuEntry) bool {
|
||||||
|
if m.isSamePage(inme.Page) {
|
||||||
|
return m.Page == inme.Page
|
||||||
|
}
|
||||||
murl, inmeurl := m.URL(), inme.URL()
|
murl, inmeurl := m.URL(), inme.URL()
|
||||||
return murl != "" && inmeurl != "" && murl == inmeurl
|
return murl != "" && inmeurl != "" && murl == inmeurl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MenuEntry) isSamePage(p Page) bool {
|
||||||
|
if !types.IsNil(m.Page) && !types.IsNil(p) {
|
||||||
|
return m.Page == p
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MenuEntry) MarshallMap(ime map[string]interface{}) {
|
func (m *MenuEntry) MarshallMap(ime map[string]interface{}) {
|
||||||
for k, v := range ime {
|
for k, v := range ime {
|
||||||
loki := strings.ToLower(k)
|
loki := strings.ToLower(k)
|
||||||
switch loki {
|
switch loki {
|
||||||
case "url":
|
case "url":
|
||||||
m.ConfiguredURL = cast.ToString(v)
|
m.ConfiguredURL = cast.ToString(v)
|
||||||
|
case "pageref":
|
||||||
|
m.PageRef = cast.ToString(v)
|
||||||
case "weight":
|
case "weight":
|
||||||
m.Weight = cast.ToInt(v)
|
m.Weight = cast.ToInt(v)
|
||||||
case "name":
|
case "name":
|
||||||
|
|
|
@ -15,6 +15,7 @@ package navigation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gohugoio/hugo/common/maps"
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
"github.com/gohugoio/hugo/common/types"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
|
@ -97,7 +98,6 @@ func PageMenusFromPage(p Page) (PageMenus, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMenuQueryProvider(
|
func NewMenuQueryProvider(
|
||||||
setionPagesMenu string,
|
|
||||||
pagem PageMenusGetter,
|
pagem PageMenusGetter,
|
||||||
sitem MenusGetter,
|
sitem MenusGetter,
|
||||||
p Page) MenuQueryProvider {
|
p Page) MenuQueryProvider {
|
||||||
|
@ -105,23 +105,18 @@ func NewMenuQueryProvider(
|
||||||
p: p,
|
p: p,
|
||||||
pagem: pagem,
|
pagem: pagem,
|
||||||
sitem: sitem,
|
sitem: sitem,
|
||||||
setionPagesMenu: setionPagesMenu,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type pageMenus struct {
|
type pageMenus struct {
|
||||||
pagem PageMenusGetter
|
pagem PageMenusGetter
|
||||||
sitem MenusGetter
|
sitem MenusGetter
|
||||||
setionPagesMenu string
|
|
||||||
p Page
|
p Page
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pageMenus) HasMenuCurrent(menuID string, me *MenuEntry) bool {
|
func (pm *pageMenus) HasMenuCurrent(menuID string, me *MenuEntry) bool {
|
||||||
// page is labeled as "shadow-member" of the menu with the same identifier as the section
|
if !types.IsNil(me.Page) && me.Page.IsSection() {
|
||||||
if pm.setionPagesMenu != "" {
|
if ok, _ := me.Page.IsAncestor(pm.p); ok {
|
||||||
section := pm.p.Section()
|
|
||||||
|
|
||||||
if section != "" && pm.setionPagesMenu == menuID && section == me.Identifier {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,18 +138,15 @@ func (pm *pageMenus) HasMenuCurrent(menuID string, me *MenuEntry) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pm.p == nil || pm.p.IsPage() {
|
if pm.p == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following logic is kept from back when Hugo had both Page and Node types.
|
|
||||||
// TODO(bep) consolidate / clean
|
|
||||||
nme := MenuEntry{Page: pm.p, Name: pm.p.LinkTitle()}
|
|
||||||
|
|
||||||
for _, child := range me.Children {
|
for _, child := range me.Children {
|
||||||
if nme.IsSameResource(child) {
|
if child.isSamePage(pm.p) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if pm.HasMenuCurrent(menuID, child) {
|
if pm.HasMenuCurrent(menuID, child) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -172,20 +164,16 @@ func (pm *pageMenus) IsMenuCurrent(menuID string, inme *MenuEntry) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pm.p == nil || pm.p.IsPage() {
|
if pm.p == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following logic is kept from back when Hugo had both Page and Node types.
|
if !inme.isSamePage(pm.p) {
|
||||||
// TODO(bep) consolidate / clean
|
|
||||||
me := MenuEntry{Page: pm.p, Name: pm.p.LinkTitle()}
|
|
||||||
|
|
||||||
if !me.IsSameResource(inme) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// this resource may be included in several menus
|
// This resource may be included in several menus.
|
||||||
// search for it to make sure that it is in the menu with the given menuId
|
// Search for it to make sure that it is in the menu with the given menuId.
|
||||||
if menu, ok := pm.sitem.Menus()[menuID]; ok {
|
if menu, ok := pm.sitem.Menus()[menuID]; ok {
|
||||||
for _, menuEntry := range menu {
|
for _, menuEntry := range menu {
|
||||||
if menuEntry.IsSameResource(inme) {
|
if menuEntry.IsSameResource(inme) {
|
||||||
|
|
Loading…
Reference in a new issue