diff options
-rw-r--r-- | hugolib/page.go | 109 | ||||
-rw-r--r-- | hugolib/page_test.go | 4 | ||||
-rw-r--r-- | hugolib/site.go | 12 | ||||
-rw-r--r-- | output/layout.go | 13 | ||||
-rw-r--r-- | output/layout_test.go | 28 |
5 files changed, 88 insertions, 78 deletions
diff --git a/hugolib/page.go b/hugolib/page.go index 554bd30cd..fb842ca37 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -36,6 +36,8 @@ import ( "time" "unicode/utf8" + "github.com/spf13/hugo/output" + "github.com/spf13/cast" bp "github.com/spf13/hugo/bufferpool" "github.com/spf13/hugo/media" @@ -204,6 +206,43 @@ type Page struct { // The media types this page will be rendered to. // TODO(bep) probably wrap this to add additional information like template evaluation? mediaTypes media.Types + + // Used to pick the correct template(s) + layoutIdentifier pageLayoutIdentifier +} + +// Implements layout.LayoutIdentifier +type pageLayoutIdentifier struct { + *Page +} + +// PageKind returns the page's kind. +func (p pageLayoutIdentifier) PageKind() string { + return p.Kind +} + +// PageLayout returns the page's layout, if set. +func (p pageLayoutIdentifier) PageLayout() string { + return p.Layout +} + +// PageType returns the page's type, if set. +func (p pageLayoutIdentifier) PageType() string { + return p.Type() +} + +// PageType returns the page's section in layout terms. +// This will be empty for regular pages, the section for section pages, +// and the singular term for taxonomy and taxonomy terms pages. +func (p pageLayoutIdentifier) PageSection() string { + switch p.Kind { + case KindSection: + return p.sections[0] + case KindTaxonomy, KindTaxonomyTerm: + return p.s.taxonomiesPluralSingular[p.sections[0]] + default: + return "" + } } // pageInit lazy initializes different parts of the page. It is extracted @@ -595,7 +634,7 @@ func (p *Page) getRenderingConfig() *helpers.Blackfriday { func (s *Site) newPage(filename string) *Page { sp := source.NewSourceSpec(s.Cfg, s.Fs) - page := Page{ + p := &Page{ pageInit: &pageInit{}, Kind: kindFromFilename(filename), contentType: "", @@ -607,9 +646,10 @@ func (s *Site) newPage(filename string) *Page { Site: &s.Info, s: s, } + p.layoutIdentifier = pageLayoutIdentifier{p} - s.Log.DEBUG.Println("Reading from", page.File.Path()) - return &page + s.Log.DEBUG.Println("Reading from", p.File.Path()) + return p } func (p *Page) IsRenderable() bool { @@ -635,44 +675,23 @@ func (p *Page) Section() string { return p.Source.Section() } -func (p *Page) layouts(l ...string) []string { +func (p *Page) layouts(layouts ...string) []string { if len(p.layoutsCalculated) > 0 { return p.layoutsCalculated } - switch p.Kind { - case KindHome: - return p.s.appendThemeTemplates([]string{"index.html", "_default/list.html"}) - case KindSection: - section := p.sections[0] - return p.s.appendThemeTemplates([]string{"section/" + section + ".html", section + "/list.html", "_default/section.html", "_default/list.html", "indexes/" + section + ".html", "_default/indexes.html"}) - case KindTaxonomy: - singular := p.s.taxonomiesPluralSingular[p.sections[0]] - return p.s.appendThemeTemplates([]string{"taxonomy/" + singular + ".html", "indexes/" + singular + ".html", "_default/taxonomy.html", "_default/list.html"}) - case KindTaxonomyTerm: - singular := p.s.taxonomiesPluralSingular[p.sections[0]] - return p.s.appendThemeTemplates([]string{"taxonomy/" + singular + ".terms.html", "_default/terms.html", "indexes/indexes.html"}) - } - - // Regular Page handled below - - if p.Layout != "" { - return layouts(p.Type(), p.Layout) + layoutOverride := "" + if len(layouts) > 0 { + layoutOverride = layouts[0] } - layout := "" - if len(l) == 0 { - layout = "single" - } else { - layout = l[0] - } - - return layouts(p.Type(), layout) + return p.s.layoutHandler.For(p.layoutIdentifier, layoutOverride, output.HTMLType) } // TODO(bep) consolidate and test these KindHome switches (see other layouts methods)s // rssLayouts returns RSS layouts to use for the RSS version of this page, nil // if no RSS should be rendered. +// TODO(bep) output func (p *Page) rssLayouts() []string { switch p.Kind { case KindHome: @@ -693,26 +712,6 @@ func (p *Page) rssLayouts() []string { return nil } -func layouts(types string, layout string) (layouts []string) { - t := strings.Split(types, "/") - - // Add type/layout.html - for i := range t { - search := t[:len(t)-i] - layouts = append(layouts, fmt.Sprintf("%s/%s.html", strings.ToLower(path.Join(search...)), layout)) - } - - // Add _default/layout.html - layouts = append(layouts, fmt.Sprintf("_default/%s.html", layout)) - - // Add theme/type/layout.html & theme/_default/layout.html - for _, l := range layouts { - layouts = append(layouts, "theme/"+l) - } - - return -} - func (s *Site) NewPageFrom(buf io.Reader, name string) (*Page, error) { p, err := s.NewPage(name) if err != nil { @@ -1360,14 +1359,8 @@ func (p *Page) Menus() PageMenus { return p.pageMenus } -func (p *Page) Render(layout ...string) template.HTML { - var l []string - - if len(layout) > 0 { - l = layouts(p.Type(), layout[0]) - } else { - l = p.layouts() - } +func (p *Page) Render(layouts ...string) template.HTML { + l := p.layouts(layouts...) return p.s.Tmpl.ExecuteTemplateToHTML(p, l...) } diff --git a/hugolib/page_test.go b/hugolib/page_test.go index ab6087647..82d6cbc8f 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -1412,6 +1412,7 @@ func TestPageSimpleMethods(t *testing.T) { } func TestIndexPageSimpleMethods(t *testing.T) { + s := newTestSite(t) t.Parallel() for i, this := range []struct { assertFunc func(n *Page) bool @@ -1422,9 +1423,10 @@ func TestIndexPageSimpleMethods(t *testing.T) { {func(n *Page) bool { return n.Scratch() != nil }}, {func(n *Page) bool { return n.Hugo() != nil }}, {func(n *Page) bool { return n.Now().Unix() == time.Now().Unix() }}, + {func(n *Page) bool { return n.layoutIdentifier.Kind == KindHome }}, } { - n := &Page{pageInit: &pageInit{}, Kind: KindHome} + n := s.newHomePage() n.RSSLink = "rssLink" diff --git a/hugolib/site.go b/hugolib/site.go index 4c8aac018..ee20ecc19 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -37,6 +37,7 @@ import ( bp "github.com/spf13/hugo/bufferpool" "github.com/spf13/hugo/deps" "github.com/spf13/hugo/helpers" + "github.com/spf13/hugo/output" "github.com/spf13/hugo/parser" "github.com/spf13/hugo/source" "github.com/spf13/hugo/tpl" @@ -100,6 +101,8 @@ type Site struct { // This is not a pointer by design. w siteWriter + layoutHandler *output.LayoutHandler + draftCount int futureCount int expiredCount int @@ -121,7 +124,7 @@ func (s *Site) isEnabled(kind string) bool { // reset returns a new Site prepared for rebuild. func (s *Site) reset() *Site { - return &Site{Deps: s.Deps, disabledKinds: s.disabledKinds, Language: s.Language, owner: s.owner, PageCollections: newPageCollections()} + return &Site{Deps: s.Deps, layoutHandler: &output.LayoutHandler{}, disabledKinds: s.disabledKinds, Language: s.Language, owner: s.owner, PageCollections: newPageCollections()} } // newSite creates a new site with the given configuration. @@ -137,7 +140,7 @@ func newSite(cfg deps.DepsCfg) (*Site, error) { disabledKinds[disabled] = true } - s := &Site{PageCollections: c, Language: cfg.Language, disabledKinds: disabledKinds} + s := &Site{PageCollections: c, layoutHandler: &output.LayoutHandler{}, Language: cfg.Language, disabledKinds: disabledKinds} s.Info = newSiteInfo(siteBuilderCfg{s: s, pageCollections: c, language: s.Language}) @@ -2038,13 +2041,16 @@ func getGoMaxProcs() int { } func (s *Site) newNodePage(typ string) *Page { - return &Page{ + p := &Page{ language: s.Language, pageInit: &pageInit{}, Kind: typ, Data: make(map[string]interface{}), Site: &s.Info, s: s} + p.layoutIdentifier = pageLayoutIdentifier{p} + return p + } func (s *Site) newHomePage() *Page { diff --git a/output/layout.go b/output/layout.go index 7646caf48..ba246237a 100644 --- a/output/layout.go +++ b/output/layout.go @@ -19,6 +19,7 @@ import ( "strings" ) +// LayoutIdentifier is used to pick the correct layout for a piece of content. type LayoutIdentifier interface { PageType() string PageSection() string // TODO(bep) name @@ -28,7 +29,7 @@ type LayoutIdentifier interface { // Layout calculates the layout template to use to render a given output type. // TODO(bep) output improve names -type Layout struct { +type LayoutHandler struct { } // TODO(bep) output theme layouts @@ -39,9 +40,15 @@ var ( layoutTaxonomyTerm = "taxonomy/SECTION.terms.html _default/terms.html indexes/indexes.html" ) -func (l *Layout) For(id LayoutIdentifier, tp Type) []string { +func (l *LayoutHandler) For(id LayoutIdentifier, layoutOverride string, tp Type) []string { var layouts []string + layout := id.PageLayout() + + if layoutOverride != "" { + layout = layoutOverride + } + switch id.PageKind() { // TODO(bep) move the Kind constants some common place. case "home": @@ -53,7 +60,7 @@ func (l *Layout) For(id LayoutIdentifier, tp Type) []string { case "taxonomyTerm": layouts = strings.Fields(strings.Replace(layoutTaxonomyTerm, "SECTION", id.PageSection(), -1)) case "page": - layouts = regularPageLayouts(id.PageType(), id.PageLayout()) + layouts = regularPageLayouts(id.PageType(), layout) } for _, l := range layouts { diff --git a/output/layout_test.go b/output/layout_test.go index 897b451c9..5b95e01d8 100644 --- a/output/layout_test.go +++ b/output/layout_test.go @@ -43,23 +43,25 @@ func (l testLayoutIdentifier) PageSection() string { } func TestLayout(t *testing.T) { - l := &Layout{} + l := &LayoutHandler{} for _, this := range []struct { - li testLayoutIdentifier - tp Type - expect []string + li testLayoutIdentifier + layoutOverride string + tp Type + expect []string }{ - {testLayoutIdentifier{"home", "", "", ""}, HTMLType, []string{"index.html", "_default/list.html", "theme/index.html", "theme/_default/list.html"}}, - {testLayoutIdentifier{"section", "sect1", "", ""}, HTMLType, []string{"section/sect1.html", "sect1/list.html"}}, - {testLayoutIdentifier{"taxonomy", "tag", "", ""}, HTMLType, []string{"taxonomy/tag.html", "indexes/tag.html"}}, - {testLayoutIdentifier{"taxonomyTerm", "categories", "", ""}, HTMLType, []string{"taxonomy/categories.terms.html", "_default/terms.html"}}, - {testLayoutIdentifier{"page", "", "", ""}, HTMLType, []string{"_default/single.html", "theme/_default/single.html"}}, - {testLayoutIdentifier{"page", "", "mylayout", ""}, HTMLType, []string{"_default/mylayout.html"}}, - {testLayoutIdentifier{"page", "", "mylayout", "myttype"}, HTMLType, []string{"myttype/mylayout.html", "_default/mylayout.html"}}, - {testLayoutIdentifier{"page", "", "mylayout", "myttype/mysubtype"}, HTMLType, []string{"myttype/mysubtype/mylayout.html", "myttype/mylayout.html", "_default/mylayout.html"}}, + {testLayoutIdentifier{"home", "", "", ""}, "", HTMLType, []string{"index.html", "_default/list.html", "theme/index.html", "theme/_default/list.html"}}, + {testLayoutIdentifier{"section", "sect1", "", ""}, "", HTMLType, []string{"section/sect1.html", "sect1/list.html"}}, + {testLayoutIdentifier{"taxonomy", "tag", "", ""}, "", HTMLType, []string{"taxonomy/tag.html", "indexes/tag.html"}}, + {testLayoutIdentifier{"taxonomyTerm", "categories", "", ""}, "", HTMLType, []string{"taxonomy/categories.terms.html", "_default/terms.html"}}, + {testLayoutIdentifier{"page", "", "", ""}, "", HTMLType, []string{"_default/single.html", "theme/_default/single.html"}}, + {testLayoutIdentifier{"page", "", "mylayout", ""}, "", HTMLType, []string{"_default/mylayout.html"}}, + {testLayoutIdentifier{"page", "", "mylayout", "myttype"}, "", HTMLType, []string{"myttype/mylayout.html", "_default/mylayout.html"}}, + {testLayoutIdentifier{"page", "", "mylayout", "myttype/mysubtype"}, "", HTMLType, []string{"myttype/mysubtype/mylayout.html", "myttype/mylayout.html", "_default/mylayout.html"}}, + {testLayoutIdentifier{"page", "", "mylayout", "myttype"}, "myotherlayout", HTMLType, []string{"myttype/myotherlayout.html", "_default/myotherlayout.html"}}, } { - layouts := l.For(this.li, this.tp) + layouts := l.For(this.li, this.layoutOverride, this.tp) require.NotNil(t, layouts) require.True(t, len(layouts) >= len(this.expect)) // Not checking the complete list for now ... |