diff --git a/docs/content/layout/templates.md b/docs/content/layout/templates.md index 833546fcc..8f21aada3 100644 --- a/docs/content/layout/templates.md +++ b/docs/content/layout/templates.md @@ -22,7 +22,7 @@ The homepage of your site. ### [RSS](/layout/rss/) Used to render all rss documents. -### [Index](/layout/index) +### [Index](/layout/indexes) Page that list multiple pieces of content. ### [Content](/layout/content) diff --git a/docs/layouts/chrome/menu.html b/docs/layouts/chrome/menu.html index 40b3b6693..89f1c8414 100644 --- a/docs/layouts/chrome/menu.html +++ b/docs/layouts/chrome/menu.html @@ -2,40 +2,40 @@
  • Home
  • -
  • Installing Hugo
  • -
  • Usage
  • -
  • Configuration
  • -
  • Source Directory Layout
  • +
  • Installing Hugo
  • +
  • Usage
  • +
  • Configuration
  • +
  • Source Directory Layout
  • Overview
  • -
  • Variables
  • -
  • Homepage
  • -
  • RSS
  • -
  • Index
  • -
  • Content
  • -
  • Content Views
  • -
  • Chrome
  • +
  • Variables
  • +
  • Homepage
  • +
  • RSS
  • +
  • Index
  • +
  • Content
  • +
  • Content Views
  • +
  • Chrome
  • -
  • Organization
  • -
  • Sections
  • -
  • Types
  • -
  • Front Matter
  • -
  • Example
  • +
  • Organization
  • +
  • Sections
  • +
  • Types
  • +
  • Front Matter
  • +
  • Example
  • -
  • ShortCodes
  • -
  • Aliases
  • -
  • Indexes
  • -
  • Example Index - Category
  • +
  • ShortCodes
  • +
  • Aliases
  • +
  • Indexes
  • +
  • Example Index - Category
  • -
  • Release Notes
  • -
  • Roadmap
  • -
  • Contributing
  • -
  • Contributors
  • -
  • License
  • +
  • Release Notes
  • +
  • Roadmap
  • +
  • Contributing
  • +
  • Contributors
  • +
  • License
  • diff --git a/hugolib/node.go b/hugolib/node.go index 91e5f92b8..c0779261c 100644 --- a/hugolib/node.go +++ b/hugolib/node.go @@ -21,7 +21,7 @@ import ( type Node struct { RSSlink template.HTML Site SiteInfo - layout string +// layout string Data map[string]interface{} Title string Description string diff --git a/hugolib/page.go b/hugolib/page.go index 44f109214..dcfa841ca 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -46,6 +46,7 @@ type Page struct { Tmpl bundle.Template Markup string renderable bool + layout string PageMeta File Position @@ -151,11 +152,14 @@ func (p *Page) IsRenderable() bool { func (p *Page) guessSection() { if p.Section == "" { x := strings.Split(p.FileName, "/") - if len(x) > 1 { - if section := x[len(x)-2]; section != "content" { - p.Section = section - } + x = x[:len(x)-1] + if len(x) == 0 { + return } + if x[0] == "content" { + x = x[1:] + } + p.Section = path.Join(x...) } } @@ -171,7 +175,11 @@ func (page *Page) Type() string { return "page" } -func (page *Page) Layout(l ...string) string { +func (page *Page) Layout(l ...string) []string { + if page.layout != "" { + return layouts(page.Type(), page.layout) + } + layout := "" if len(l) == 0 { layout = "single" @@ -179,11 +187,17 @@ func (page *Page) Layout(l ...string) string { layout = l[0] } - if x := page.layout; x != "" { - return x - } + return layouts(page.Type(), layout) +} - return strings.ToLower(page.Type()) + "/" + layout + ".html" +func layouts(types string, layout string) (layouts []string) { + t := strings.Split(types, "/") + for i := range t { + search := t[:len(t)-i] + layouts = append(layouts, fmt.Sprintf("%s/%s.html", strings.ToLower(path.Join(search...)), layout)) + } + layouts = append(layouts, fmt.Sprintf("%s.html", layout)) + return } func ReadFrom(buf io.Reader, name string) (page *Page, err error) { @@ -214,7 +228,7 @@ func (p *Page) permalink() (*url.URL, error) { pUrl := strings.TrimSpace(p.Url) var permalink string if len(pSlug) > 0 { - if p.Site.Config.UglyUrls { + if p.Site.Config != nil && p.Site.Config.UglyUrls { permalink = section + "/" + p.Slug + "." + p.Extension } else { permalink = section + "/" + p.Slug + "/" @@ -404,7 +418,12 @@ func (p *Page) Render(layout ...string) template.HTML { func (p *Page) ExecuteTemplate(layout string) *bytes.Buffer { l := p.Layout(layout) buffer := new(bytes.Buffer) - p.Tmpl.ExecuteTemplate(buffer, l, p) + for _, layout := range l { + if p.Tmpl.Lookup(layout) != nil { + p.Tmpl.ExecuteTemplate(buffer, layout, p) + break + } + } return buffer } diff --git a/hugolib/page_permalink_test.go b/hugolib/page_permalink_test.go new file mode 100644 index 000000000..d318505b8 --- /dev/null +++ b/hugolib/page_permalink_test.go @@ -0,0 +1,9 @@ +package hugolib + +import ( + "testing" +) + +func TestPermalink(t *testing.T) { + +} diff --git a/hugolib/page_test.go b/hugolib/page_test.go index 33da04e5d..4832cc4f3 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -180,8 +180,8 @@ func checkPageType(t *testing.T, page *Page, pageType string) { } } -func checkPageLayout(t *testing.T, page *Page, layout string) { - if page.Layout() != layout { +func checkPageLayout(t *testing.T, page *Page, layout ...string) { + if !listEqual(page.Layout(), layout) { t.Fatalf("Page layout is: %s. Expected: %s", page.Layout(), layout) } } @@ -201,7 +201,7 @@ func TestCreateNewPage(t *testing.T) { checkPageContent(t, p, "

    Simple Page

    \n") checkPageSummary(t, p, "Simple Page") checkPageType(t, p, "page") - checkPageLayout(t, p, "page/single.html") + checkPageLayout(t, p, "page/single.html", "single.html") } func TestPageWithDelimiter(t *testing.T) { @@ -213,7 +213,7 @@ func TestPageWithDelimiter(t *testing.T) { checkPageContent(t, p, "

    Summary Next Line

    \n\n

    Some more text

    \n") checkPageSummary(t, p, "

    Summary Next Line

    \n") checkPageType(t, p, "page") - checkPageLayout(t, p, "page/single.html") + checkPageLayout(t, p, "page/single.html", "single.html") } func TestPageWithShortCodeInSummary(t *testing.T) { @@ -225,7 +225,7 @@ func TestPageWithShortCodeInSummary(t *testing.T) { checkPageContent(t, p, "

    Summary Next Line. {{% img src=“/not/real” %}}.\nMore text here.

    \n\n

    Some more text

    \n") checkPageSummary(t, p, "Summary Next Line. . More text here. Some more text") checkPageType(t, p, "page") - checkPageLayout(t, p, "page/single.html") + checkPageLayout(t, p, "page/single.html", "single.html") } func TestPageWithMoreTag(t *testing.T) { @@ -237,7 +237,7 @@ func TestPageWithMoreTag(t *testing.T) { checkPageContent(t, p, "

    Summary Same Line

    \n\n

    Some more text

    \n") checkPageSummary(t, p, "

    Summary Same Line

    \n") checkPageType(t, p, "page") - checkPageLayout(t, p, "page/single.html") + checkPageLayout(t, p, "page/single.html", "single.html") } func TestPageWithDate(t *testing.T) { @@ -315,10 +315,14 @@ func TestSectionEvaluation(t *testing.T) { } } +func L(s ...string) []string { + return s +} + func TestLayoutOverride(t *testing.T) { var ( - path_content_one_dir = path.Join("content", "gub", "file1.md") path_content_two_dir = path.Join("content", "dub", "sub", "file1.md") + path_content_one_dir = path.Join("content", "gub", "file1.md") path_content_no_dir = path.Join("content", "file1") path_one_directory = path.Join("fub", "file1.md") path_no_directory = path.Join("file1.md") @@ -326,35 +330,49 @@ func TestLayoutOverride(t *testing.T) { tests := []struct { content string path string - expectedLayout string + expectedLayout []string }{ - {SIMPLE_PAGE_NOLAYOUT, path_content_two_dir, "sub/single.html"}, - {SIMPLE_PAGE_NOLAYOUT, path_content_one_dir, "gub/single.html"}, - {SIMPLE_PAGE_NOLAYOUT, path_content_no_dir, "page/single.html"}, - {SIMPLE_PAGE_NOLAYOUT, path_one_directory, "fub/single.html"}, - {SIMPLE_PAGE_NOLAYOUT, path_no_directory, "page/single.html"}, - {SIMPLE_PAGE_LAYOUT_FOOBAR, path_content_two_dir, "foobar"}, - {SIMPLE_PAGE_LAYOUT_FOOBAR, path_content_one_dir, "foobar"}, - {SIMPLE_PAGE_LAYOUT_FOOBAR, path_one_directory, "foobar"}, - {SIMPLE_PAGE_LAYOUT_FOOBAR, path_no_directory, "foobar"}, - {SIMPLE_PAGE_TYPE_FOOBAR, path_content_two_dir, "foobar/single.html"}, - {SIMPLE_PAGE_TYPE_FOOBAR, path_content_one_dir, "foobar/single.html"}, - {SIMPLE_PAGE_TYPE_FOOBAR, path_content_no_dir, "foobar/single.html"}, - {SIMPLE_PAGE_TYPE_FOOBAR, path_one_directory, "foobar/single.html"}, - {SIMPLE_PAGE_TYPE_FOOBAR, path_no_directory, "foobar/single.html"}, - {SIMPLE_PAGE_TYPE_LAYOUT, path_content_two_dir, "buzfoo"}, - {SIMPLE_PAGE_TYPE_LAYOUT, path_content_one_dir, "buzfoo"}, - {SIMPLE_PAGE_TYPE_LAYOUT, path_content_no_dir, "buzfoo"}, - {SIMPLE_PAGE_TYPE_LAYOUT, path_one_directory, "buzfoo"}, - {SIMPLE_PAGE_TYPE_LAYOUT, path_no_directory, "buzfoo"}, + {SIMPLE_PAGE_NOLAYOUT, path_content_two_dir, L("dub/sub/single.html", "dub/single.html", "single.html")}, + {SIMPLE_PAGE_NOLAYOUT, path_content_one_dir, L("gub/single.html", "single.html")}, + {SIMPLE_PAGE_NOLAYOUT, path_content_no_dir, L("page/single.html", "single.html")}, + {SIMPLE_PAGE_NOLAYOUT, path_one_directory, L("fub/single.html", "single.html")}, + {SIMPLE_PAGE_NOLAYOUT, path_no_directory, L("page/single.html", "single.html")}, + {SIMPLE_PAGE_LAYOUT_FOOBAR, path_content_two_dir, L("dub/sub/foobar.html", "dub/foobar.html", "foobar.html")}, + {SIMPLE_PAGE_LAYOUT_FOOBAR, path_content_one_dir, L("gub/foobar.html", "foobar.html")}, + {SIMPLE_PAGE_LAYOUT_FOOBAR, path_one_directory, L("fub/foobar.html", "foobar.html")}, + {SIMPLE_PAGE_LAYOUT_FOOBAR, path_no_directory, L("page/foobar.html", "foobar.html")}, + {SIMPLE_PAGE_TYPE_FOOBAR, path_content_two_dir, L("foobar/single.html", "single.html")}, + {SIMPLE_PAGE_TYPE_FOOBAR, path_content_one_dir, L("foobar/single.html", "single.html")}, + {SIMPLE_PAGE_TYPE_FOOBAR, path_content_no_dir, L("foobar/single.html", "single.html")}, + {SIMPLE_PAGE_TYPE_FOOBAR, path_one_directory, L("foobar/single.html", "single.html")}, + {SIMPLE_PAGE_TYPE_FOOBAR, path_no_directory, L("foobar/single.html", "single.html")}, + {SIMPLE_PAGE_TYPE_LAYOUT, path_content_two_dir, L("barfoo/buzfoo.html", "buzfoo.html")}, + {SIMPLE_PAGE_TYPE_LAYOUT, path_content_one_dir, L("barfoo/buzfoo.html", "buzfoo.html")}, + {SIMPLE_PAGE_TYPE_LAYOUT, path_content_no_dir, L("barfoo/buzfoo.html", "buzfoo.html")}, + {SIMPLE_PAGE_TYPE_LAYOUT, path_one_directory, L("barfoo/buzfoo.html", "buzfoo.html")}, + {SIMPLE_PAGE_TYPE_LAYOUT, path_no_directory, L("barfoo/buzfoo.html", "buzfoo.html")}, } for _, test := range tests { p, err := ReadFrom(strings.NewReader(test.content), test.path) if err != nil { t.Fatalf("Unable to parse content:\n%s\n", test.content) } - if p.Layout() != test.expectedLayout { + if !listEqual(p.Layout(), test.expectedLayout) { t.Errorf("Layout mismatch. Expected: %s, got: %s", test.expectedLayout, p.Layout()) } } } + +func listEqual(left, right []string) bool { + if len(left) != len(right) { + return false + } + + for i := range left { + if left[i] != right[i] { + return false + } + } + + return true +} diff --git a/hugolib/path_seperators_test.go b/hugolib/path_seperators_test.go index 1c7f7eb10..50a9eedae 100644 --- a/hugolib/path_seperators_test.go +++ b/hugolib/path_seperators_test.go @@ -26,25 +26,26 @@ func TestNewPageWithFilePath(t *testing.T) { toCheck := []struct { input string section string - layout string + layout []string }{ - {path.Join("sub", "foobar.html"), "sub", "sub/single.html"}, - {path.Join("content", "sub", "foobar.html"), "sub", "sub/single.html"}, - {path.Join("content", "dub", "sub", "foobar.html"), "sub", "sub/single.html"}, + {path.Join("sub", "foobar.html"), "sub", L("sub/single.html", "single.html")}, + {path.Join("content", "foobar.html"), "", L("page/single.html", "single.html")}, + {path.Join("content", "sub", "foobar.html"), "sub", L("sub/single.html", "single.html")}, + {path.Join("content", "dub", "sub", "foobar.html"), "dub/sub", L("dub/sub/single.html", "dub/single.html", "single.html")}, } for _, el := range toCheck { p, err := ReadFrom(strings.NewReader(SIMPLE_PAGE_YAML), el.input) p.guessSection() if err != nil { - t.Fatalf("Reading from SIMPLE_PAGE_YAML resulted in an error: %s", err) + t.Errorf("Reading from SIMPLE_PAGE_YAML resulted in an error: %s", err) } if p.Section != el.section { - t.Fatalf("Section not set to %s for page %s. Got: %s", el.section, el.input, p.Section) + t.Errorf("Section not set to %s for page %s. Got: %s", el.section, el.input, p.Section) } - if p.Layout() != el.layout { - t.Fatalf("Layout incorrect. Expected: '%s', Got: '%s'", el.layout, p.Layout()) + if !listEqual(p.Layout(), el.layout) { + t.Errorf("Layout incorrect. Expected: '%s', Got: '%s'", el.layout, p.Layout()) } } } diff --git a/hugolib/planner.go b/hugolib/planner.go index 637c27b10..246312746 100644 --- a/hugolib/planner.go +++ b/hugolib/planner.go @@ -18,7 +18,9 @@ func (s *Site) ShowPlan(out io.Writer) (err error) { fmt.Fprintf(out, " (renderer: n/a)") } if s.Tmpl != nil { - fmt.Fprintf(out, " (layout: %s, exists: %t)", p.Layout(), s.Tmpl.Lookup(p.Layout()) != nil) + for _, l := range p.Layout() { + fmt.Fprintf(out, " (layout: %s, exists: %t)", l, s.Tmpl.Lookup(l) != nil) + } } fmt.Fprintf(out, "\n") fmt.Fprintf(out, " canonical => ") diff --git a/hugolib/site.go b/hugolib/site.go index 782bafbb7..e5d4fab44 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -67,6 +67,7 @@ type Site struct { Transformer transform.Transformer Target target.Output Alias target.AliasPublisher + Completed chan bool } type SiteInfo struct { @@ -364,19 +365,21 @@ func (s *Site) RenderAliases() error { func (s *Site) RenderPages() (err error) { for _, p := range s.Pages { - var layout string + var layout []string if !p.IsRenderable() { - layout = "__" + p.TargetPath() - _, err := s.Tmpl.New(layout).Parse(string(p.Content)) + self := "__" + p.TargetPath() + _, err := s.Tmpl.New(self).Parse(string(p.Content)) if err != nil { return err } + layout = append(layout, self) } else { - layout = p.Layout() + layout = append(layout, p.Layout()...) + layout = append(layout, "_default/single.html") } - err := s.render(p, p.TargetPath(), layout, "_default/single.html") + err := s.render(p, p.TargetPath(), layout...) if err != nil { return err } @@ -484,7 +487,7 @@ func (s *Site) RenderHomePage() error { n.Data["Pages"] = s.Pages[:9] } } - err := s.render(n, "/", "index.html") + err := s.render(n, "/", "index.html", "_default/single.html") if err != nil { return err } @@ -554,8 +557,6 @@ func (s *Site) render(d interface{}, out string, layouts ...string) (err error) section, _ = page.RelPermalink() } - fmt.Println("Section is:", section) - transformer := transform.NewChain( &transform.AbsURL{BaseURL: s.Config.BaseUrl}, &transform.NavActive{Section: section}, diff --git a/hugolib/site_test.go b/hugolib/site_test.go index dbc738b5c..7fb562f92 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -227,7 +227,7 @@ func TestSkipRender(t *testing.T) { s := &Site{ Target: target, - Config: Config{BaseUrl: "http://auth/bub/"}, + Config: Config{Verbose: true, BaseUrl: "http://auth/bub/"}, Source: &source.InMemorySource{sources}, } s.initializeSiteInfo()