mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
node to page: Handle home
With refactored paginator handling. Updates #2297
This commit is contained in:
parent
e371ac0b6f
commit
734b6508a1
4 changed files with 145 additions and 45 deletions
|
@ -18,6 +18,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -54,6 +55,9 @@ Home **Content!**
|
|||
Index Title: {{ .Title }}
|
||||
Index Content: {{ .Content }}
|
||||
# Pages: {{ len .Data.Pages }}
|
||||
{{ range .Paginator.Pages }}
|
||||
Pag: {{ .Title }}
|
||||
{{ end }}
|
||||
`)
|
||||
|
||||
writeSource(t, filepath.Join("layouts", "_default", "single.html"), `
|
||||
|
@ -70,6 +74,8 @@ Content Page %d
|
|||
`, i, i))
|
||||
}
|
||||
|
||||
viper.Set("paginate", 3)
|
||||
|
||||
s := newSiteDefaultLang()
|
||||
|
||||
if err := buildAndRenderSite(s); err != nil {
|
||||
|
@ -80,6 +86,7 @@ Content Page %d
|
|||
"Index Title: Home Sweet Home!",
|
||||
"Home <strong>Content!</strong>",
|
||||
"# Pages: 10")
|
||||
|
||||
assertFileContent(t, filepath.Join("public", "regular1", "index.html"), false, "Single Title: Page 1", "Content Page 1")
|
||||
|
||||
h := s.owner
|
||||
|
@ -100,4 +107,11 @@ Content Page %d
|
|||
require.False(t, first.IsNode())
|
||||
require.True(t, first.IsPage())
|
||||
|
||||
first.Paginator()
|
||||
|
||||
// Check paginator
|
||||
assertFileContent(t, filepath.Join("public", "page", "3", "index.html"), false,
|
||||
"Pag: Page 6",
|
||||
"Pag: Page 7")
|
||||
|
||||
}
|
||||
|
|
|
@ -1173,3 +1173,97 @@ func (p *Page) TargetPath() (outfile string) {
|
|||
return p.addLangFilepathPrefix(filepath.Join(strings.ToLower(
|
||||
p.Site.pathSpec.MakePath(p.Source.Dir())), strings.TrimSpace(outfile)))
|
||||
}
|
||||
|
||||
// Pre render prepare steps
|
||||
|
||||
func (p *Page) prepareLayouts() error {
|
||||
// TODO(bep): Check the IsRenderable logic.
|
||||
if p.NodeType == NodePage {
|
||||
var layouts []string
|
||||
if !p.IsRenderable() {
|
||||
self := "__" + p.TargetPath()
|
||||
_, err := p.Site.owner.tmpl.GetClone().New(self).Parse(string(p.Content))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layouts = append(layouts, self)
|
||||
} else {
|
||||
layouts = append(layouts, p.layouts()...)
|
||||
layouts = append(layouts, "_default/single.html")
|
||||
}
|
||||
p.layoutsCalculated = layouts
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Page) prepareData() error {
|
||||
switch p.NodeType {
|
||||
case NodePage:
|
||||
case NodeHome:
|
||||
p.Data = make(map[string]interface{})
|
||||
// TODO(bep) np cache the below
|
||||
// TODO(bep) np
|
||||
p.Data["Pages"] = p.Site.owner.findPagesByNodeType(NodePage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// renderPaginator must be run after the owning Page has been rendered.
|
||||
// TODO(bep) np
|
||||
func (p *Page) renderPaginator(s *Site) error {
|
||||
if p.paginator != nil {
|
||||
paginatePath := helpers.Config().GetString("paginatePath")
|
||||
|
||||
{
|
||||
// write alias for page 1
|
||||
// TODO(bep) ml all of these n.addLang ... fix.
|
||||
permaLink, _ := p.Permalink()
|
||||
s.writeDestAlias(p.addLangPathPrefix(helpers.PaginateAliasPath("", 1)), permaLink, nil)
|
||||
}
|
||||
|
||||
pagers := p.paginator.Pagers()
|
||||
|
||||
for i, pager := range pagers {
|
||||
if i == 0 {
|
||||
// already created
|
||||
continue
|
||||
}
|
||||
|
||||
pagerNode := p.copy()
|
||||
|
||||
pagerNode.paginator = pager
|
||||
if pager.TotalPages() > 0 {
|
||||
first, _ := pager.page(0)
|
||||
pagerNode.Date = first.Date
|
||||
pagerNode.Lastmod = first.Lastmod
|
||||
}
|
||||
|
||||
pageNumber := i + 1
|
||||
htmlBase := fmt.Sprintf("/%s/%d", paginatePath, pageNumber)
|
||||
htmlBase = p.addLangPathPrefix(htmlBase)
|
||||
if err := s.renderAndWritePage(pagerNode.Title,
|
||||
filepath.FromSlash(htmlBase), pagerNode, p.layouts()...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Page constains some sync.Once which have a mutex, so we cannot just
|
||||
// copy the Page by value. So for the situations where we need a copy,
|
||||
// the paginators etc., we do it manually here.
|
||||
// TODO(bep) np do better
|
||||
func (p *Page) copy() *Page {
|
||||
c := &Page{Node: Node{NodeType: p.NodeType}}
|
||||
c.Title = p.Title
|
||||
c.Data = p.Data
|
||||
c.Date = p.Date
|
||||
c.Lastmod = p.Lastmod
|
||||
c.language = p.language
|
||||
c.lang = p.lang
|
||||
c.URLPath = p.URLPath
|
||||
return c
|
||||
}
|
||||
|
|
|
@ -260,7 +260,9 @@ func splitPageGroups(pageGroups PagesGroup, size int) []paginatedElement {
|
|||
// Paginator gets this Node's paginator if it's already created.
|
||||
// If it's not, one will be created with all pages in Data["Pages"].
|
||||
func (n *Node) Paginator(options ...interface{}) (*Pager, error) {
|
||||
|
||||
if !n.NodeType.IsNode() {
|
||||
return nil, errors.New("Paginators not supported for content pages.")
|
||||
}
|
||||
pagerSize, err := resolvePagerSize(options...)
|
||||
|
||||
if err != nil {
|
||||
|
@ -297,20 +299,13 @@ func (n *Node) Paginator(options ...interface{}) (*Pager, error) {
|
|||
return n.paginator, nil
|
||||
}
|
||||
|
||||
// Paginator on Page isn't supported, calling this yields an error.
|
||||
func (p *Page) Paginator(options ...interface{}) (*Pager, error) {
|
||||
return nil, errors.New("Paginators not supported for content pages.")
|
||||
}
|
||||
|
||||
// Paginate on Page isn't supported, calling this yields an error.
|
||||
func (p *Page) Paginate(seq interface{}, options ...interface{}) (*Pager, error) {
|
||||
return nil, errors.New("Paginators not supported for content pages.")
|
||||
}
|
||||
|
||||
// Paginate gets this Node's paginator if it's already created.
|
||||
// If it's not, one will be created with the qiven sequence.
|
||||
// Note that repeated calls will return the same result, even if the sequence is different.
|
||||
func (n *Node) Paginate(seq interface{}, options ...interface{}) (*Pager, error) {
|
||||
if !n.NodeType.IsNode() {
|
||||
return nil, errors.New("Paginators not supported for content pages.")
|
||||
}
|
||||
|
||||
pagerSize, err := resolvePagerSize(options...)
|
||||
|
||||
|
|
|
@ -848,9 +848,15 @@ func (s *Site) render() (err error) {
|
|||
return
|
||||
}
|
||||
s.timerStep("render and write lists")
|
||||
|
||||
if err = s.preparePages(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.renderPages(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.timerStep("render and write pages")
|
||||
if err = s.renderHomePage(false); err != nil {
|
||||
return
|
||||
|
@ -1620,6 +1626,25 @@ func (s *Site) renderAliases() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Site) preparePages() error {
|
||||
var errors []error
|
||||
|
||||
for _, p := range s.Pages {
|
||||
if err := p.prepareLayouts(); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
if err := p.prepareData(); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errors) != 0 {
|
||||
return fmt.Errorf("Prepare pages failed: %.100q…", errors)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// renderPages renders pages each corresponding to a markdown file.
|
||||
func (s *Site) renderPages() error {
|
||||
|
||||
|
@ -1631,26 +1656,6 @@ func (s *Site) renderPages() error {
|
|||
|
||||
procs := getGoMaxProcs()
|
||||
|
||||
// this cannot be fanned out to multiple Go routines
|
||||
// See issue #1601
|
||||
// TODO(bep): Check the IsRenderable logic.
|
||||
for _, p := range s.Pages {
|
||||
var layouts []string
|
||||
if !p.IsRenderable() {
|
||||
self := "__" + p.TargetPath()
|
||||
_, err := s.owner.tmpl.GetClone().New(self).Parse(string(p.Content))
|
||||
if err != nil {
|
||||
results <- err
|
||||
continue
|
||||
}
|
||||
layouts = append(layouts, self)
|
||||
} else {
|
||||
layouts = append(layouts, p.layouts()...)
|
||||
layouts = append(layouts, "_default/single.html")
|
||||
}
|
||||
p.layoutsCalculated = layouts
|
||||
}
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
|
||||
for i := 0; i < procs*4; i++ {
|
||||
|
@ -1678,23 +1683,15 @@ func (s *Site) renderPages() error {
|
|||
func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
for p := range pages {
|
||||
// TODO(bep) np paginator
|
||||
s.preparePage(p)
|
||||
err := s.renderAndWritePage("page "+p.FullFilePath(), p.TargetPath(), p, s.appendThemeTemplates(p.layouts())...)
|
||||
if err != nil {
|
||||
if err := s.renderAndWritePage("page "+p.FullFilePath(), p.TargetPath(), p, s.appendThemeTemplates(p.layouts())...); err != nil {
|
||||
results <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Site) preparePage(p *Page) {
|
||||
// TODO(bep) np the order of it all
|
||||
switch p.NodeType {
|
||||
case NodePage:
|
||||
case NodeHome:
|
||||
p.Data = make(map[string]interface{})
|
||||
// TODO(bep) np cache the below
|
||||
p.Data["Pages"] = s.owner.findPagesByNodeType(NodePage)
|
||||
if p.NodeType.IsNode() {
|
||||
if err := p.renderPaginator(s); err != nil {
|
||||
results <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue