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"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,6 +55,9 @@ Home **Content!**
|
||||||
Index Title: {{ .Title }}
|
Index Title: {{ .Title }}
|
||||||
Index Content: {{ .Content }}
|
Index Content: {{ .Content }}
|
||||||
# Pages: {{ len .Data.Pages }}
|
# Pages: {{ len .Data.Pages }}
|
||||||
|
{{ range .Paginator.Pages }}
|
||||||
|
Pag: {{ .Title }}
|
||||||
|
{{ end }}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
writeSource(t, filepath.Join("layouts", "_default", "single.html"), `
|
writeSource(t, filepath.Join("layouts", "_default", "single.html"), `
|
||||||
|
@ -70,6 +74,8 @@ Content Page %d
|
||||||
`, i, i))
|
`, i, i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viper.Set("paginate", 3)
|
||||||
|
|
||||||
s := newSiteDefaultLang()
|
s := newSiteDefaultLang()
|
||||||
|
|
||||||
if err := buildAndRenderSite(s); err != nil {
|
if err := buildAndRenderSite(s); err != nil {
|
||||||
|
@ -80,6 +86,7 @@ Content Page %d
|
||||||
"Index Title: Home Sweet Home!",
|
"Index Title: Home Sweet Home!",
|
||||||
"Home <strong>Content!</strong>",
|
"Home <strong>Content!</strong>",
|
||||||
"# Pages: 10")
|
"# Pages: 10")
|
||||||
|
|
||||||
assertFileContent(t, filepath.Join("public", "regular1", "index.html"), false, "Single Title: Page 1", "Content Page 1")
|
assertFileContent(t, filepath.Join("public", "regular1", "index.html"), false, "Single Title: Page 1", "Content Page 1")
|
||||||
|
|
||||||
h := s.owner
|
h := s.owner
|
||||||
|
@ -100,4 +107,11 @@ Content Page %d
|
||||||
require.False(t, first.IsNode())
|
require.False(t, first.IsNode())
|
||||||
require.True(t, first.IsPage())
|
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(
|
return p.addLangFilepathPrefix(filepath.Join(strings.ToLower(
|
||||||
p.Site.pathSpec.MakePath(p.Source.Dir())), strings.TrimSpace(outfile)))
|
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.
|
// 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"].
|
// If it's not, one will be created with all pages in Data["Pages"].
|
||||||
func (n *Node) Paginator(options ...interface{}) (*Pager, error) {
|
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...)
|
pagerSize, err := resolvePagerSize(options...)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -297,20 +299,13 @@ func (n *Node) Paginator(options ...interface{}) (*Pager, error) {
|
||||||
return n.paginator, nil
|
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.
|
// Paginate gets this Node's paginator if it's already created.
|
||||||
// If it's not, one will be created with the qiven sequence.
|
// 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.
|
// 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) {
|
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...)
|
pagerSize, err := resolvePagerSize(options...)
|
||||||
|
|
||||||
|
|
|
@ -848,9 +848,15 @@ func (s *Site) render() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.timerStep("render and write lists")
|
s.timerStep("render and write lists")
|
||||||
|
|
||||||
|
if err = s.preparePages(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err = s.renderPages(); err != nil {
|
if err = s.renderPages(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.timerStep("render and write pages")
|
s.timerStep("render and write pages")
|
||||||
if err = s.renderHomePage(false); err != nil {
|
if err = s.renderHomePage(false); err != nil {
|
||||||
return
|
return
|
||||||
|
@ -1620,6 +1626,25 @@ func (s *Site) renderAliases() error {
|
||||||
return nil
|
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.
|
// renderPages renders pages each corresponding to a markdown file.
|
||||||
func (s *Site) renderPages() error {
|
func (s *Site) renderPages() error {
|
||||||
|
|
||||||
|
@ -1631,26 +1656,6 @@ func (s *Site) renderPages() error {
|
||||||
|
|
||||||
procs := getGoMaxProcs()
|
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{}
|
wg := &sync.WaitGroup{}
|
||||||
|
|
||||||
for i := 0; i < procs*4; i++ {
|
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) {
|
func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for p := range pages {
|
for p := range pages {
|
||||||
// TODO(bep) np paginator
|
if err := s.renderAndWritePage("page "+p.FullFilePath(), p.TargetPath(), p, s.appendThemeTemplates(p.layouts())...); err != nil {
|
||||||
s.preparePage(p)
|
|
||||||
err := s.renderAndWritePage("page "+p.FullFilePath(), p.TargetPath(), p, s.appendThemeTemplates(p.layouts())...)
|
|
||||||
if err != nil {
|
|
||||||
results <- err
|
results <- err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Site) preparePage(p *Page) {
|
if p.NodeType.IsNode() {
|
||||||
// TODO(bep) np the order of it all
|
if err := p.renderPaginator(s); err != nil {
|
||||||
switch p.NodeType {
|
results <- err
|
||||||
case NodePage:
|
}
|
||||||
case NodeHome:
|
}
|
||||||
p.Data = make(map[string]interface{})
|
|
||||||
// TODO(bep) np cache the below
|
|
||||||
p.Data["Pages"] = s.owner.findPagesByNodeType(NodePage)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue