summaryrefslogtreecommitdiffstats
path: root/hugolib/site_sections.go
diff options
context:
space:
mode:
Diffstat (limited to 'hugolib/site_sections.go')
-rw-r--r--hugolib/site_sections.go273
1 files changed, 67 insertions, 206 deletions
diff --git a/hugolib/site_sections.go b/hugolib/site_sections.go
index 38f6a3b6f..d383e6389 100644
--- a/hugolib/site_sections.go
+++ b/hugolib/site_sections.go
@@ -1,4 +1,4 @@
-// Copyright 2017 The Hugo Authors. All rights reserved.
+// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,18 +14,18 @@
package hugolib
import (
- "fmt"
"path"
"strconv"
"strings"
- "github.com/gohugoio/hugo/helpers"
+ "github.com/gohugoio/hugo/resources/page"
+ "github.com/gohugoio/hugo/resources/resource"
radix "github.com/hashicorp/go-immutable-radix"
)
// Sections returns the top level sections.
-func (s *SiteInfo) Sections() Pages {
+func (s *SiteInfo) Sections() page.Pages {
home, err := s.Home()
if err == nil {
return home.Sections()
@@ -34,157 +34,23 @@ func (s *SiteInfo) Sections() Pages {
}
// Home is a shortcut to the home page, equivalent to .Site.GetPage "home".
-func (s *SiteInfo) Home() (*Page, error) {
- return s.GetPage(KindHome)
+func (s *SiteInfo) Home() (page.Page, error) {
+ return s.s.home, nil
}
-// Parent returns a section's parent section or a page's section.
-// To get a section's subsections, see Page's Sections method.
-func (p *Page) Parent() *Page {
- return p.parent
-}
-
-// CurrentSection returns the page's current section or the page itself if home or a section.
-// Note that this will return nil for pages that is not regular, home or section pages.
-func (p *Page) CurrentSection() *Page {
- v := p
- if v.origOnCopy != nil {
- v = v.origOnCopy
- }
- if v.IsHome() || v.IsSection() {
- return v
- }
-
- return v.parent
-}
-
-// FirstSection returns the section on level 1 below home, e.g. "/docs".
-// For the home page, this will return itself.
-func (p *Page) FirstSection() *Page {
- v := p
- if v.origOnCopy != nil {
- v = v.origOnCopy
- }
-
- if v.parent == nil || v.parent.IsHome() {
- return v
- }
-
- parent := v.parent
- for {
- current := parent
- parent = parent.parent
- if parent == nil || parent.IsHome() {
- return current
- }
- }
-
-}
-
-// InSection returns whether the given page is in the current section.
-// Note that this will always return false for pages that are
-// not either regular, home or section pages.
-func (p *Page) InSection(other interface{}) (bool, error) {
- if p == nil || other == nil {
- return false, nil
- }
-
- pp, err := unwrapPage(other)
- if err != nil {
- return false, err
- }
-
- if pp == nil {
- return false, nil
- }
-
- return pp.CurrentSection() == p.CurrentSection(), nil
-}
-
-// IsDescendant returns whether the current page is a descendant of the given page.
-// Note that this method is not relevant for taxonomy lists and taxonomy terms pages.
-func (p *Page) IsDescendant(other interface{}) (bool, error) {
- if p == nil {
- return false, nil
- }
- pp, err := unwrapPage(other)
- if err != nil || pp == nil {
- return false, err
- }
-
- if pp.Kind == KindPage && len(p.sections) == len(pp.sections) {
- // A regular page is never its section's descendant.
- return false, nil
- }
- return helpers.HasStringsPrefix(p.sections, pp.sections), nil
-}
-
-// IsAncestor returns whether the current page is an ancestor of the given page.
-// Note that this method is not relevant for taxonomy lists and taxonomy terms pages.
-func (p *Page) IsAncestor(other interface{}) (bool, error) {
- if p == nil {
- return false, nil
- }
+func (s *Site) assembleSections() pageStatePages {
+ var newPages pageStatePages
- pp, err := unwrapPage(other)
- if err != nil || pp == nil {
- return false, err
- }
-
- if p.Kind == KindPage && len(p.sections) == len(pp.sections) {
- // A regular page is never its section's ancestor.
- return false, nil
- }
-
- return helpers.HasStringsPrefix(pp.sections, p.sections), nil
-}
-
-// Eq returns whether the current page equals the given page.
-// Note that this is more accurate than doing `{{ if eq $page $otherPage }}`
-// since a Page can be embedded in another type.
-func (p *Page) Eq(other interface{}) bool {
- pp, err := unwrapPage(other)
- if err != nil {
- return false
- }
-
- return p == pp
-}
-
-func unwrapPage(in interface{}) (*Page, error) {
- switch v := in.(type) {
- case *Page:
- return v, nil
- case *PageOutput:
- return v.Page, nil
- case *PageWithoutContent:
- return v.Page, nil
- case nil:
- return nil, nil
- default:
- return nil, fmt.Errorf("%T not supported", in)
- }
-}
-
-// Sections returns this section's subsections, if any.
-// Note that for non-sections, this method will always return an empty list.
-func (p *Page) Sections() Pages {
- return p.subSections
-}
-
-func (s *Site) assembleSections() Pages {
- var newPages Pages
-
- if !s.isEnabled(KindSection) {
+ if !s.isEnabled(page.KindSection) {
return newPages
}
// Maps section kind pages to their path, i.e. "my/section"
- sectionPages := make(map[string]*Page)
+ sectionPages := make(map[string]*pageState)
// The sections with content files will already have been created.
- for _, sect := range s.findPagesByKind(KindSection) {
- sectionPages[path.Join(sect.sections...)] = sect
+ for _, sect := range s.findWorkPagesByKind(page.KindSection) {
+ sectionPages[sect.SectionsPath()] = sect
}
const (
@@ -196,39 +62,44 @@ func (s *Site) assembleSections() Pages {
var (
inPages = radix.New().Txn()
inSections = radix.New().Txn()
- undecided Pages
+ undecided pageStatePages
)
- home := s.findFirstPageByKindIn(KindHome, s.Pages)
+ home := s.findFirstWorkPageByKindIn(page.KindHome)
- for i, p := range s.Pages {
- if p.Kind != KindPage {
+ for i, p := range s.workAllPages {
+
+ if p.Kind() != page.KindPage {
continue
}
- if len(p.sections) == 0 {
+ sections := p.SectionsEntries()
+
+ if len(sections) == 0 {
// Root level pages. These will have the home page as their Parent.
p.parent = home
continue
}
- sectionKey := path.Join(p.sections...)
- sect, found := sectionPages[sectionKey]
+ sectionKey := p.SectionsPath()
+ _, found := sectionPages[sectionKey]
+
+ if !found && len(sections) == 1 {
- if !found && len(p.sections) == 1 {
// We only create content-file-less sections for the root sections.
- sect = s.newSectionPage(p.sections[0])
- sectionPages[sectionKey] = sect
- newPages = append(newPages, sect)
+ n := s.newPage(page.KindSection, sections[0])
+
+ sectionPages[sectionKey] = n
+ newPages = append(newPages, n)
found = true
}
- if len(p.sections) > 1 {
+ if len(sections) > 1 {
// Create the root section if not found.
- _, rootFound := sectionPages[p.sections[0]]
+ _, rootFound := sectionPages[sections[0]]
if !rootFound {
- sect = s.newSectionPage(p.sections[0])
- sectionPages[p.sections[0]] = sect
+ sect := s.newPage(page.KindSection, sections[0])
+ sectionPages[sections[0]] = sect
newPages = append(newPages, sect)
}
}
@@ -246,13 +117,14 @@ func (s *Site) assembleSections() Pages {
// given a content file in /content/a/b/c/_index.md, we cannot create just
// the c section.
for _, sect := range sectionPages {
- for i := len(sect.sections); i > 0; i-- {
- sectionPath := sect.sections[:i]
+ sections := sect.SectionsEntries()
+ for i := len(sections); i > 0; i-- {
+ sectionPath := sections[:i]
sectionKey := path.Join(sectionPath...)
- sect, found := sectionPages[sectionKey]
+ _, found := sectionPages[sectionKey]
if !found {
- sect = s.newSectionPage(sectionPath[len(sectionPath)-1])
- sect.sections = sectionPath
+ sect = s.newPage(page.KindSection, sectionPath[len(sectionPath)-1])
+ sect.m.sections = sectionPath
sectionPages[sectionKey] = sect
newPages = append(newPages, sect)
}
@@ -265,33 +137,36 @@ func (s *Site) assembleSections() Pages {
}
var (
- currentSection *Page
- children Pages
+ currentSection *pageState
+ children page.Pages
+ dates *resource.Dates
rootSections = inSections.Commit().Root()
)
for i, p := range undecided {
// Now we can decide where to put this page into the tree.
- sectionKey := path.Join(p.sections...)
+ sectionKey := p.SectionsPath()
+
_, v, _ := rootSections.LongestPrefix([]byte(sectionKey))
- sect := v.(*Page)
- pagePath := path.Join(path.Join(sect.sections...), sectSectKey, "u", strconv.Itoa(i))
+ sect := v.(*pageState)
+ pagePath := path.Join(path.Join(sect.SectionsEntries()...), sectSectKey, "u", strconv.Itoa(i))
inPages.Insert([]byte(pagePath), p)
}
var rootPages = inPages.Commit().Root()
rootPages.Walk(func(path []byte, v interface{}) bool {
- p := v.(*Page)
+ p := v.(*pageState)
- if p.Kind == KindSection {
+ if p.Kind() == page.KindSection {
if currentSection != nil {
// A new section
- currentSection.setPagePages(children)
+ currentSection.setPages(children)
}
currentSection = p
- children = make(Pages, 0)
+ children = make(page.Pages, 0)
+ dates = &resource.Dates{}
return false
@@ -300,27 +175,31 @@ func (s *Site) assembleSections() Pages {
// Regular page
p.parent = currentSection
children = append(children, p)
+ dates.UpdateDateAndLastmodIfAfter(p)
return false
})
if currentSection != nil {
- currentSection.setPagePages(children)
+ currentSection.setPages(children)
+ currentSection.m.Dates = *dates
+
}
// Build the sections hierarchy
for _, sect := range sectionPages {
- if len(sect.sections) == 1 {
- sect.parent = home
+ sections := sect.SectionsEntries()
+ if len(sections) == 1 {
+ if home != nil {
+ sect.parent = home
+ }
} else {
- parentSearchKey := path.Join(sect.sections[:len(sect.sections)-1]...)
+ parentSearchKey := path.Join(sect.SectionsEntries()[:len(sections)-1]...)
_, v, _ := rootSections.LongestPrefix([]byte(parentSearchKey))
- p := v.(*Page)
+ p := v.(*pageState)
sect.parent = p
}
- if sect.parent != nil {
- sect.parent.subSections = append(sect.parent.subSections, sect)
- }
+ sect.addSectionToParent()
}
var (
@@ -331,24 +210,13 @@ func (s *Site) assembleSections() Pages {
maxSectionWeight int
)
- mainSections, mainSectionsFound = s.Info.Params[sectionsParamIdLower]
+ mainSections, mainSectionsFound = s.Info.Params()[sectionsParamIdLower]
for _, sect := range sectionPages {
- if sect.parent != nil {
- sect.parent.subSections.sort()
- }
-
- for i, p := range sect.Pages {
- if i > 0 {
- p.NextInSection = sect.Pages[i-1]
- }
- if i < len(sect.Pages)-1 {
- p.PrevInSection = sect.Pages[i+1]
- }
- }
+ sect.sortParentSections()
if !mainSectionsFound {
- weight := len(sect.Pages) + (len(sect.Sections()) * 5)
+ weight := len(sect.Pages()) + (len(sect.Sections()) * 5)
if weight >= maxSectionWeight {
mainSections = []string{sect.Section()}
maxSectionWeight = weight
@@ -357,16 +225,9 @@ func (s *Site) assembleSections() Pages {
}
// Try to make this as backwards compatible as possible.
- s.Info.Params[sectionsParamId] = mainSections
- s.Info.Params[sectionsParamIdLower] = mainSections
+ s.Info.Params()[sectionsParamId] = mainSections
+ s.Info.Params()[sectionsParamIdLower] = mainSections
return newPages
}
-
-func (p *Page) setPagePages(pages Pages) {
- pages.sort()
- p.Pages = pages
- p.data = make(map[string]interface{})
- p.data["Pages"] = pages
-}