summaryrefslogtreecommitdiffstats
path: root/hugolib/site_sections.go
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-04-09 10:33:04 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-06-08 11:21:34 +0200
commitb39689393ccb8434d9a57658a64b77568c718e99 (patch)
tree944d679ac8e908444eb00d0d405ec3c131f31bab /hugolib/site_sections.go
parentbef5048580b38b0c29edef4eb8c67915033120e9 (diff)
hugolib: Enable nested sections
Fixes #465
Diffstat (limited to 'hugolib/site_sections.go')
-rw-r--r--hugolib/site_sections.go295
1 files changed, 295 insertions, 0 deletions
diff --git a/hugolib/site_sections.go b/hugolib/site_sections.go
new file mode 100644
index 000000000..151baac84
--- /dev/null
+++ b/hugolib/site_sections.go
@@ -0,0 +1,295 @@
+// Copyright 2017 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.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+ "fmt"
+ "path"
+ "strconv"
+ "strings"
+
+ radix "github.com/hashicorp/go-immutable-radix"
+ "github.com/spf13/hugo/helpers"
+)
+
+// Deprecated: Use .Site.Home.Sections.
+// TODO(bep) Hugo 0.23 = Reuse as an alias for home's sections.
+func (s *SiteInfo) Sections() Taxonomy {
+
+ helpText := `In Hugo 0.22 we introduced nested sections, so this method now returns an empty taxonomy.
+
+To list sections with its pages, you can do something like this:
+
+{{ range $.Site.Home.Sections }}
+ Section: {{ .Title }}
+ {{ range .Pages }}
+ Section Page: {{ .Title }}
+ {{ end }}
+{{ end }}
+
+To get a specific section, you can do this:
+
+{{ $section := $.Site.GetPage "section" "blog" }}
+`
+
+ helpers.Deprecated("Site", "Sections", helpText, true)
+
+ return Taxonomy{}
+}
+
+// Home is a shortcut to the home page, equivalent to .Site.GetPage "home".
+func (s *SiteInfo) Home() (*Page, error) {
+ return s.GetPage(KindHome)
+}
+
+// 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
+}
+
+// current returns the page's current section.
+// Note that this will return nil for pages that is not regular, home or section pages.
+// Note that for paginated sections and home pages, this will return the original page pointer.
+func (p *Page) current() *Page {
+ v := p
+ if v.origOnCopy != nil {
+ v = v.origOnCopy
+ }
+ if v.IsHome() || v.IsSection() {
+ return v
+ }
+
+ return v.parent
+}
+
+// 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
+ }
+
+ if po, ok := other.(*PageOutput); ok {
+ other = po.Page
+ }
+
+ pp, ok := other.(*Page)
+ if !ok {
+ return false, fmt.Errorf("%T not supported in InSection", other)
+ }
+
+ if pp == nil {
+ return false, nil
+ }
+
+ return pp.current() == p.current(), nil
+}
+
+// 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) {
+ return newPages
+ }
+
+ // Maps section kind pages to their path, i.e. "my/section"
+ sectionPages := make(map[string]*Page)
+
+ // The sections with content files will already have been created.
+ for _, sect := range s.findPagesByKind(KindSection) {
+ sectionPages[path.Join(sect.sections...)] = sect
+ }
+
+ const (
+ sectKey = "__hs"
+ sectSectKey = "_a" + sectKey
+ sectPageKey = "_b" + sectKey
+ )
+
+ var (
+ home *Page
+ inPages = radix.New().Txn()
+ inSections = radix.New().Txn()
+ undecided Pages
+ )
+
+ for i, p := range s.Pages {
+ if p.Kind != KindPage {
+ if p.Kind == KindHome {
+ home = p
+ }
+ continue
+ }
+
+ if len(p.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]
+
+ 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)
+ } else if !found {
+ // We don't know what to do with this section yet.
+ undecided = append(undecided, p)
+ }
+
+ pagePath := path.Join(sectionKey, sectPageKey, strconv.Itoa(i))
+ inPages.Insert([]byte(pagePath), p)
+ }
+
+ // Create any missing sections in the tree.
+ // A sub-section needs a content file, but to create a navigational tree,
+ // 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]
+ sectionKey := path.Join(sectionPath...)
+ sect, found := sectionPages[sectionKey]
+ if !found {
+ sect = s.newSectionPage(sectionPath[len(sectionPath)-1])
+ sect.sections = sectionPath
+ sectionPages[sectionKey] = sect
+ newPages = append(newPages, sect)
+ }
+ }
+ }
+
+ // Create any missing root sections.
+ for _, p := range undecided {
+ sectionKey := p.sections[0]
+ sect, found := sectionPages[sectionKey]
+ if !found {
+ sect = s.newSectionPage(sectionKey)
+ sectionPages[sectionKey] = sect
+ newPages = append(newPages, sect)
+ }
+ }
+
+ for k, sect := range sectionPages {
+ inPages.Insert([]byte(path.Join(k, sectSectKey)), sect)
+ inSections.Insert([]byte(k), sect)
+ }
+
+ var (
+ currentSection *Page
+ children Pages
+ rootPages = inPages.Commit().Root()
+ rootSections = inSections.Commit().Root()
+ )
+
+ rootPages.Walk(func(path []byte, v interface{}) bool {
+ p := v.(*Page)
+
+ if p.Kind == KindSection {
+ if currentSection != nil {
+ // A new section
+ currentSection.setPagePages(children)
+ }
+
+ currentSection = p
+ children = make(Pages, 0)
+
+ return false
+
+ }
+
+ // Regular page
+ p.parent = currentSection
+ children = append(children, p)
+ return false
+ })
+
+ if currentSection != nil {
+ currentSection.setPagePages(children)
+ }
+
+ // Build the sections hierarchy
+ for _, sect := range sectionPages {
+ if len(sect.sections) == 1 {
+ sect.parent = home
+ } else {
+ parentSearchKey := path.Join(sect.sections[:len(sect.sections)-1]...)
+ _, v, _ := rootSections.LongestPrefix([]byte(parentSearchKey))
+ p := v.(*Page)
+ sect.parent = p
+ }
+
+ if sect.parent != nil {
+ sect.parent.subSections = append(sect.parent.subSections, sect)
+ }
+ }
+
+ var (
+ sectionsParamId = "mainSections"
+ sectionsParamIdLower = strings.ToLower(sectionsParamId)
+ mainSections interface{}
+ mainSectionsFound bool
+ maxSectionWeight int
+ )
+
+ 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]
+ }
+ }
+
+ if !mainSectionsFound {
+ weight := len(sect.Pages) + (len(sect.Sections()) * 5)
+ if weight >= maxSectionWeight {
+ mainSections = []string{sect.Section()}
+ maxSectionWeight = weight
+ }
+ }
+ }
+
+ // Try to make this as backwards compatible as possible.
+ 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
+}