diff options
Diffstat (limited to 'resources/page')
-rw-r--r-- | resources/page/page.go | 10 | ||||
-rw-r--r-- | resources/page/page_marshaljson.autogen.go | 6 | ||||
-rw-r--r-- | resources/page/page_nop.go | 2 | ||||
-rw-r--r-- | resources/page/pagegroup.go | 2 | ||||
-rw-r--r-- | resources/page/pagegroup_test.go | 13 | ||||
-rw-r--r-- | resources/page/pagemeta/page_frontmatter.go | 331 | ||||
-rw-r--r-- | resources/page/pagemeta/page_frontmatter_test.go | 31 | ||||
-rw-r--r-- | resources/page/pagemeta/pagemeta.go | 4 | ||||
-rw-r--r-- | resources/page/pagination.go | 12 | ||||
-rw-r--r-- | resources/page/pagination_test.go | 6 | ||||
-rw-r--r-- | resources/page/site.go | 11 | ||||
-rw-r--r-- | resources/page/site_integration_test.go | 44 |
12 files changed, 427 insertions, 45 deletions
diff --git a/resources/page/page.go b/resources/page/page.go index f995ee641..9647a916b 100644 --- a/resources/page/page.go +++ b/resources/page/page.go @@ -225,9 +225,6 @@ type PageMetaProvider interface { // to the source of this Page. It will be relative to any content root. Path() string - // This is for internal use only. - PathInfo() *paths.Path - // The slug, typically defined in front matter. Slug() string @@ -253,6 +250,12 @@ type PageMetaProvider interface { Weight() int } +// PageMetaInternalProvider provides internal page metadata. +type PageMetaInternalProvider interface { + // This is for internal use only. + PathInfo() *paths.Path +} + // PageRenderProvider provides a way for a Page to render content. type PageRenderProvider interface { // Render renders the given layout with this Page as context. @@ -273,6 +276,7 @@ type PageWithoutContent interface { RenderShortcodesProvider resource.Resource PageMetaProvider + PageMetaInternalProvider resource.LanguageProvider // For pages backed by a file. diff --git a/resources/page/page_marshaljson.autogen.go b/resources/page/page_marshaljson.autogen.go index 18ed2a75d..3b2138801 100644 --- a/resources/page/page_marshaljson.autogen.go +++ b/resources/page/page_marshaljson.autogen.go @@ -17,9 +17,8 @@ package page import ( "encoding/json" - "time" - "github.com/gohugoio/hugo/config" + "time" ) func MarshalPageToJSON(p Page) ([]byte, error) { @@ -39,7 +38,6 @@ func MarshalPageToJSON(p Page) ([]byte, error) { isNode := p.IsNode() isPage := p.IsPage() path := p.Path() - pathc := p.Path() slug := p.Slug() lang := p.Lang() isSection := p.IsSection() @@ -65,7 +63,6 @@ func MarshalPageToJSON(p Page) ([]byte, error) { IsNode bool IsPage bool Path string - Pathc string Slug string Lang string IsSection bool @@ -90,7 +87,6 @@ func MarshalPageToJSON(p Page) ([]byte, error) { IsNode: isNode, IsPage: isPage, Path: path, - Pathc: pathc, Slug: slug, Lang: lang, IsSection: isSection, diff --git a/resources/page/page_nop.go b/resources/page/page_nop.go index d3813337d..f745d8622 100644 --- a/resources/page/page_nop.go +++ b/resources/page/page_nop.go @@ -57,7 +57,7 @@ var ( // PageNop implements Page, but does nothing. type nopPage int -var noOpPathInfo = paths.Parse(files.ComponentFolderContent, "no-op.md") +var noOpPathInfo = media.DefaultPathParser.Parse(files.ComponentFolderContent, "no-op.md") func (p *nopPage) Err() resource.ResourceError { return nil diff --git a/resources/page/pagegroup.go b/resources/page/pagegroup.go index 7129fae17..081708d62 100644 --- a/resources/page/pagegroup.go +++ b/resources/page/pagegroup.go @@ -205,7 +205,7 @@ func (p Pages) GroupByParam(key string, order ...string) (PagesGroup, error) { } } if !tmp.IsValid() { - return nil, errors.New("there is no such param") + return nil, nil } for _, e := range p { diff --git a/resources/page/pagegroup_test.go b/resources/page/pagegroup_test.go index 91f05b24a..5008aa720 100644 --- a/resources/page/pagegroup_test.go +++ b/resources/page/pagegroup_test.go @@ -142,15 +142,6 @@ func TestGroupByCalledWithEmptyPages(t *testing.T) { } } -func TestGroupByParamCalledWithUnavailableKey(t *testing.T) { - t.Parallel() - pages := preparePageGroupTestPages(t) - _, err := pages.GroupByParam("UnavailableKey") - if err == nil { - t.Errorf("GroupByParam should return an error but didn't") - } -} - func TestReverse(t *testing.T) { t.Parallel() pages := preparePageGroupTestPages(t) @@ -256,8 +247,8 @@ func TestGroupByParamCalledWithUnavailableParam(t *testing.T) { t.Parallel() pages := preparePageGroupTestPages(t) _, err := pages.GroupByParam("unavailable_param") - if err == nil { - t.Errorf("GroupByParam should return an error but didn't") + if err != nil { + t.Errorf("GroupByParam returned an error when it shouldn't") } } diff --git a/resources/page/pagemeta/page_frontmatter.go b/resources/page/pagemeta/page_frontmatter.go index 123dd4b70..c901ab57b 100644 --- a/resources/page/pagemeta/page_frontmatter.go +++ b/resources/page/pagemeta/page_frontmatter.go @@ -14,14 +14,24 @@ package pagemeta import ( + "errors" + "fmt" + "path" "strings" "time" + "github.com/gohugoio/hugo/common/hreflect" "github.com/gohugoio/hugo/common/htime" + "github.com/gohugoio/hugo/common/hugio" "github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/common/paths" + "github.com/gohugoio/hugo/hugofs/files" + "github.com/gohugoio/hugo/markup" + "github.com/gohugoio/hugo/media" + "github.com/gohugoio/hugo/resources/kinds" "github.com/gohugoio/hugo/resources/page" + "github.com/gohugoio/hugo/resources/resource" "github.com/gohugoio/hugo/helpers" @@ -29,6 +39,13 @@ import ( "github.com/spf13/cast" ) +type DatesStrings struct { + Date string `json:"date"` + Lastmod string `json:"lastMod"` + PublishDate string `json:"publishDate"` + ExpiryDate string `json:"expiryDate"` +} + type Dates struct { Date time.Time Lastmod time.Time @@ -57,40 +74,231 @@ func (d Dates) IsAllDatesZero() bool { // Note that all the top level fields are reserved Hugo keywords. // Any custom configuration needs to be set in the Params map. type PageConfig struct { - Dates // Dates holds the four core dates for this page. + Dates Dates `json:"-"` // Dates holds the four core dates for this page. + DatesStrings Title string // The title of the page. LinkTitle string // The link title of the page. Type string // The content type of the page. Layout string // The layout to use for to render this page. - Markup string // The markup used in the content file. Weight int // The weight of the page, used in sorting if set to a non-zero value. Kind string // The kind of page, e.g. "page", "section", "home" etc. This is usually derived from the content path. Path string // The canonical path to the page, e.g. /sect/mypage. Note: Leading slash, no trailing slash, no extensions or language identifiers. - URL string // The URL to the rendered page, e.g. /sect/mypage.html. Lang string // The language code for this page. This is usually derived from the module mount or filename. + URL string // The URL to the rendered page, e.g. /sect/mypage.html. Slug string // The slug for this page. Description string // The description for this page. Summary string // The summary for this page. Draft bool // Whether or not the content is a draft. - Headless bool // Whether or not the page should be rendered. + Headless bool `json:"-"` // Whether or not the page should be rendered. IsCJKLanguage bool // Whether or not the content is in a CJK language. TranslationKey string // The translation key for this page. Keywords []string // The keywords for this page. Aliases []string // The aliases for this page. Outputs []string // The output formats to render this page in. If not set, the site's configured output formats for this page kind will be used. - // These build options are set in the front matter, - // but not passed on to .Params. - Resources []map[string]any - Cascade map[page.PageMatcher]maps.Params // Only relevant for branch nodes. - Sitemap config.SitemapConfig - Build BuildConfig + FrontMatterOnlyValues `mapstructure:"-" json:"-"` + + Cascade []map[string]any + Sitemap config.SitemapConfig + Build BuildConfig + Menus []string // User defined params. Params maps.Params + // Content holds the content for this page. + Content Source + + // Compiled values. + CascadeCompiled map[page.PageMatcher]maps.Params + ContentMediaType media.Type `mapstructure:"-" json:"-"` + IsFromContentAdapter bool `mapstructure:"-" json:"-"` +} + +var DefaultPageConfig = PageConfig{ + Build: DefaultBuildConfig, +} + +func (p *PageConfig) Validate(pagesFromData bool) error { + if pagesFromData { + if p.Path == "" { + return errors.New("path must be set") + } + if strings.HasPrefix(p.Path, "/") { + return fmt.Errorf("path %q must not start with a /", p.Path) + } + if p.Lang != "" { + return errors.New("lang must not be set") + } + + if p.Content.Markup != "" { + return errors.New("markup must not be set, use mediaType") + } + } + + if p.Cascade != nil { + if !kinds.IsBranch(p.Kind) { + return errors.New("cascade is only supported for branch nodes") + } + } + + return nil +} + +// Compile sets up the page configuration after all fields have been set. +func (p *PageConfig) Compile(basePath string, pagesFromData bool, ext string, logger loggers.Logger, mediaTypes media.Types) error { + // In content adapters, we always get relative paths. + if basePath != "" { + p.Path = path.Join(basePath, p.Path) + } + + if p.Params == nil { + p.Params = make(maps.Params) + } + maps.PrepareParams(p.Params) + + if p.Content.Markup == "" && p.Content.MediaType == "" { + if ext == "" { + ext = "md" + } + p.ContentMediaType = MarkupToMediaType(ext, mediaTypes) + if p.ContentMediaType.IsZero() { + return fmt.Errorf("failed to resolve media type for suffix %q", ext) + } + } + + var s string + if p.ContentMediaType.IsZero() { + if p.Content.MediaType != "" { + s = p.Content.MediaType + p.ContentMediaType, _ = mediaTypes.GetByType(s) + } + + if p.ContentMediaType.IsZero() && p.Content.Markup != "" { + s = p.Content.Markup + p.ContentMediaType = MarkupToMediaType(s, mediaTypes) + } + } + + if p.ContentMediaType.IsZero() { + return fmt.Errorf("failed to resolve media type for %q", s) + } + + if p.Content.Markup == "" { + p.Content.Markup = p.ContentMediaType.SubType + } + + if pagesFromData { + if p.Kind == "" { + p.Kind = kinds.KindPage + } + + // Note that NormalizePathStringBasic will make sure that we don't preserve the unnormalized path. + // We do that when we create pages from the file system; mostly for backward compatibility, + // but also because people tend to use use the filename to name their resources (with spaces and all), + // and this isn't relevant when creating resources from an API where it's easy to add textual meta data. + p.Path = paths.NormalizePathStringBasic(p.Path) + } + + if p.Cascade != nil { + cascade, err := page.DecodeCascade(logger, p.Cascade) + if err != nil { + return fmt.Errorf("failed to decode cascade: %w", err) + } + p.CascadeCompiled = cascade + } + + return nil +} + +// MarkupToMediaType converts a markup string to a media type. +func MarkupToMediaType(s string, mediaTypes media.Types) media.Type { + s = strings.ToLower(s) + mt, _ := mediaTypes.GetBestMatch(markup.ResolveMarkup(s)) + return mt +} + +type ResourceConfig struct { + Path string + Name string + Title string + Params maps.Params + Content Source + // Compiled values. - IsGoldmark bool `json:"-"` + PathInfo *paths.Path `mapstructure:"-" json:"-"` + ContentMediaType media.Type +} + +func (rc *ResourceConfig) Validate() error { + if rc.Path == "" { + return errors.New("path must be set") + } + if rc.Content.Markup != "" { + return errors.New("markup must not be set, use mediaType") + } + return nil +} + +func (rc *ResourceConfig) Compile(basePath string, pathParser *paths.PathParser, mediaTypes media.Types) error { + if rc.Params != nil { + maps.PrepareParams(rc.Params) + } + + // Note that NormalizePathStringBasic will make sure that we don't preserve the unnormalized path. + // We do that when we create resources from the file system; mostly for backward compatibility, + // but also because people tend to use use the filename to name their resources (with spaces and all), + // and this isn't relevant when creating resources from an API where it's easy to add textual meta data. + rc.Path = paths.NormalizePathStringBasic(path.Join(basePath, rc.Path)) + rc.PathInfo = pathParser.Parse(files.ComponentFolderContent, rc.Path) + if rc.Content.MediaType != "" { + var found bool + rc.ContentMediaType, found = mediaTypes.GetByType(rc.Content.MediaType) + if !found { + return fmt.Errorf("media type %q not found", rc.Content.MediaType) + } + } + return nil +} + +type Source struct { + // MediaType is the media type of the content. + MediaType string + + // The markup used in Value. Only used in front matter. + Markup string + + // The content. + Value any +} + +func (s Source) IsZero() bool { + return !hreflect.IsTruthful(s.Value) +} + +func (s Source) IsResourceValue() bool { + _, ok := s.Value.(resource.Resource) + return ok +} + +func (s Source) ValueAsString() string { + if s.Value == nil { + return "" + } + ss, err := cast.ToStringE(s.Value) + if err != nil { + panic(fmt.Errorf("content source: failed to convert %T to string: %s", s.Value, err)) + } + return ss +} + +func (s Source) ValueAsOpenReadSeekCloser() hugio.OpenReadSeekCloser { + return hugio.NewOpenReadSeekCloser(hugio.NewReadSeekerNoOpCloserFromString(s.ValueAsString())) +} + +// FrontMatterOnlyValues holds values that can only be set via front matter. +type FrontMatterOnlyValues struct { + ResourcesMeta []map[string]any } // FrontMatterHandler maps front matter into Page fields and .Params. @@ -98,6 +306,8 @@ type PageConfig struct { type FrontMatterHandler struct { fmConfig FrontmatterConfig + contentAdapterDatesHandler func(d *FrontMatterDescriptor) error + dateHandler frontMatterFieldHandler lastModHandler frontMatterFieldHandler publishDateHandler frontMatterFieldHandler @@ -144,6 +354,13 @@ func (f FrontMatterHandler) HandleDates(d *FrontMatterDescriptor) error { panic("missing pageConfig") } + if d.PageConfig.IsFromContentAdapter { + if f.contentAdapterDatesHandler == nil { + panic("missing content adapter date handler") + } + return f.contentAdapterDatesHandler(d) + } + if f.dateHandler == nil { panic("missing date handler") } @@ -352,9 +569,13 @@ func NewFrontmatterHandler(logger loggers.Logger, frontMatterConfig FrontmatterC func (f *FrontMatterHandler) createHandlers() error { var err error + if f.contentAdapterDatesHandler, err = f.createContentAdapterDatesHandler(f.fmConfig); err != nil { + return err + } + if f.dateHandler, err = f.createDateHandler(f.fmConfig.Date, func(d *FrontMatterDescriptor, t time.Time) { - d.PageConfig.Date = t + d.PageConfig.Dates.Date = t setParamIfNotSet(fmDate, t, d) }); err != nil { return err @@ -363,7 +584,7 @@ func (f *FrontMatterHandler) createHandlers() error { if f.lastModHandler, err = f.createDateHandler(f.fmConfig.Lastmod, func(d *FrontMatterDescriptor, t time.Time) { setParamIfNotSet(fmLastmod, t, d) - d.PageConfig.Lastmod = t + d.PageConfig.Dates.Lastmod = t }); err != nil { return err } @@ -371,7 +592,7 @@ func (f *FrontMatterHandler) createHandlers() error { if f.publishDateHandler, err = f.createDateHandler(f.fmConfig.PublishDate, func(d *FrontMatterDescriptor, t time.Time) { setParamIfNotSet(fmPubDate, t, d) - d.PageConfig.PublishDate = t + d.PageConfig.Dates.PublishDate = t }); err != nil { return err } @@ -379,7 +600,7 @@ func (f *FrontMatterHandler) createHandlers() error { if f.expiryDateHandler, err = f.createDateHandler(f.fmConfig.ExpiryDate, func(d *FrontMatterDescriptor, t time.Time) { setParamIfNotSet(fmExpiryDate, t, d) - d.PageConfig.ExpiryDate = t + d.PageConfig.Dates.ExpiryDate = t }); err != nil { return err } @@ -394,6 +615,86 @@ func setParamIfNotSet(key string, value any, d *FrontMatterDescriptor) { d.PageConfig.Params[key] = value } +func (f FrontMatterHandler) createContentAdapterDatesHandler(fmcfg FrontmatterConfig) (func(d *FrontMatterDescriptor) error, error) { + setTime := func(key string, value time.Time, in *PageConfig) { + switch key { + case fmDate: + in.Dates.Date = value + case fmLastmod: + in.Dates.Lastmod = value + case fmPubDate: + in.Dates.PublishDate = value + case fmExpiryDate: + in.Dates.ExpiryDate = value + } + } + + getTime := func(key string, in *PageConfig) time.Time { + switch key { + case fmDate: + return in.Dates.Date + case fmLastmod: + return in.Dates.Lastmod + case fmPubDate: + return in.Dates.PublishDate + case fmExpiryDate: + return in.Dates.ExpiryDate + } + return time.Time{} + } + + createSetter := func(identifiers []string, date string) func(pcfg *PageConfig) { + var getTimes []func(in *PageConfig) time.Time + for _, identifier := range identifiers { + if strings.HasPrefix(identifier, ":") { + continue + } + switch identifier { + case fmDate: + getTimes = append(getTimes, func(in *PageConfig) time.Time { + return getTime(fmDate, in) + }) + case fmLastmod: + getTimes = append(getTimes, func(in *PageConfig) time.Time { + return getTime(fmLastmod, in) + }) + case fmPubDate: + getTimes = append(getTimes, func(in *PageConfig) time.Time { + return getTime(fmPubDate, in) + }) + case fmExpiryDate: + getTimes = append(getTimes, func(in *PageConfig) time.Time { + return getTime(fmExpiryDate, in) + }) + } + } + + return func(pcfg *PageConfig) { + for _, get := range getTimes { + if t := get(pcfg); !t.IsZero() { + setTime(date, t, pcfg) + return + } + } + } + } + + setDate := createSetter(fmcfg.Date, fmDate) + setLastmod := createSetter(fmcfg.Lastmod, fmLastmod) + setPublishDate := createSetter(fmcfg.PublishDate, fmPubDate) + setExpiryDate := createSetter(fmcfg.ExpiryDate, fmExpiryDate) + + fn := func(d *FrontMatterDescriptor) error { + pcfg := d.PageConfig + setDate(pcfg) + setLastmod(pcfg) + setPublishDate(pcfg) + setExpiryDate(pcfg) + return nil + } + return fn, nil +} + func (f FrontMatterHandler) createDateHandler(identifiers []string, setter func(d *FrontMatterDescriptor, t time.Time)) (frontMatterFieldHandler, error) { var h *frontmatterFieldHandlers var handlers []frontMatterFieldHandler diff --git a/resources/page/pagemeta/page_frontmatter_test.go b/resources/page/pagemeta/page_frontmatter_test.go index 9e1151f22..18f9e5aa1 100644 --- a/resources/page/pagemeta/page_frontmatter_test.go +++ b/resources/page/pagemeta/page_frontmatter_test.go @@ -18,8 +18,10 @@ import ( "testing" "time" + "github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/config/testconfig" + "github.com/gohugoio/hugo/media" "github.com/gohugoio/hugo/resources/page/pagemeta" @@ -148,3 +150,32 @@ func TestFrontMatterDatesDefaultKeyword(t *testing.T) { c.Assert(d.PageConfig.Dates.PublishDate.Day(), qt.Equals, 4) c.Assert(d.PageConfig.Dates.ExpiryDate.IsZero(), qt.Equals, true) } + +func TestContentMediaTypeFromMarkup(t *testing.T) { + c := qt.New(t) + logger := loggers.NewDefault() + + for _, test := range []struct { + in string + expected string + }{ + {"", "text/markdown"}, + {"md", "text/markdown"}, + {"markdown", "text/markdown"}, + {"mdown", "text/markdown"}, + {"goldmark", "text/markdown"}, + {"html", "text/html"}, + {"htm", "text/html"}, + {"asciidoc", "text/asciidoc"}, + {"asciidocext", "text/asciidoc"}, + {"adoc", "text/asciidoc"}, + {"pandoc", "text/pandoc"}, + {"pdc", "text/pandoc"}, + {"rst", "text/rst"}, + } { + var pc pagemeta.PageConfig + pc.Content.Markup = test.in + c.Assert(pc.Compile("", true, "", logger, media.DefaultTypes), qt.IsNil) + c.Assert(pc.ContentMediaType.Type, qt.Equals, test.expected) + } +} diff --git a/resources/page/pagemeta/pagemeta.go b/resources/page/pagemeta/pagemeta.go index f5b6380bc..b6b953231 100644 --- a/resources/page/pagemeta/pagemeta.go +++ b/resources/page/pagemeta/pagemeta.go @@ -24,7 +24,7 @@ const ( Link = "link" ) -var defaultBuildConfig = BuildConfig{ +var DefaultBuildConfig = BuildConfig{ List: Always, Render: Always, PublishResources: true, @@ -69,7 +69,7 @@ func (b BuildConfig) IsZero() bool { } func DecodeBuildConfig(m any) (BuildConfig, error) { - b := defaultBuildConfig + b := DefaultBuildConfig if m == nil { return b, nil } diff --git a/resources/page/pagination.go b/resources/page/pagination.go index 4beb96e50..ea49d62f6 100644 --- a/resources/page/pagination.go +++ b/resources/page/pagination.go @@ -19,6 +19,7 @@ import ( "math" "reflect" + "github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/config" "github.com/spf13/cast" @@ -194,7 +195,14 @@ func (p *Paginator) Pagers() pagers { } // PageSize returns the size of each paginator page. +// Deprecated: Use PagerSize instead. func (p *Paginator) PageSize() int { + hugo.Deprecate("PageSize", "Use PagerSize instead.", "v0.128.0") + return p.size +} + +// PagerSize returns the size of each paginator page. +func (p *Paginator) PagerSize() int { return p.size } @@ -263,7 +271,7 @@ func splitPageGroups(pageGroups PagesGroup, size int) []paginatedElement { func ResolvePagerSize(conf config.AllProvider, options ...any) (int, error) { if len(options) == 0 { - return conf.Paginate(), nil + return conf.Pagination().PagerSize, nil } if len(options) > 1 { @@ -400,7 +408,7 @@ func newPaginationURLFactory(d TargetPathDescriptor) paginationURLFactory { pathDescriptor := d var rel string if pageNumber > 1 { - rel = fmt.Sprintf("/%s/%d/", d.PathSpec.Cfg.PaginatePath(), pageNumber) + rel = fmt.Sprintf("/%s/%d/", d.PathSpec.Cfg.Pagination().Path, pageNumber) pathDescriptor.Addends = rel } diff --git a/resources/page/pagination_test.go b/resources/page/pagination_test.go index 487b36adb..d3a770eaf 100644 --- a/resources/page/pagination_test.go +++ b/resources/page/pagination_test.go @@ -114,7 +114,7 @@ func doTestPages(t *testing.T, paginator *Paginator) { c.Assert(len(paginatorPages), qt.Equals, 5) c.Assert(paginator.TotalNumberOfElements(), qt.Equals, 21) - c.Assert(paginator.PageSize(), qt.Equals, 5) + c.Assert(paginator.PagerSize(), qt.Equals, 5) c.Assert(paginator.TotalPages(), qt.Equals, 5) first := paginatorPages[0] @@ -172,7 +172,7 @@ func doTestPagerNoPages(t *testing.T, paginator *Paginator) { c := qt.New(t) c.Assert(len(paginatorPages), qt.Equals, 1) c.Assert(paginator.TotalNumberOfElements(), qt.Equals, 0) - c.Assert(paginator.PageSize(), qt.Equals, 5) + c.Assert(paginator.PagerSize(), qt.Equals, 5) c.Assert(paginator.TotalPages(), qt.Equals, 0) // pageOne should be nothing but the first @@ -187,7 +187,7 @@ func doTestPagerNoPages(t *testing.T, paginator *Paginator) { c.Assert(pageOne.TotalNumberOfElements(), qt.Equals, 0) c.Assert(pageOne.TotalPages(), qt.Equals, 0) c.Assert(pageOne.PageNumber(), qt.Equals, 1) - c.Assert(pageOne.PageSize(), qt.Equals, 5) + c.Assert(pageOne.PagerSize(), qt.Equals, 5) } func TestProbablyEqualPageLists(t *testing.T) { diff --git a/resources/page/site.go b/resources/page/site.go index df33485eb..56f438cb6 100644 --- a/resources/page/site.go +++ b/resources/page/site.go @@ -139,8 +139,15 @@ type Site interface { // Sites represents an ordered list of sites (languages). type Sites []Site -// First is a convenience method to get the first Site, i.e. the main language. +// Deprecated: Use .Sites.Default instead. func (s Sites) First() Site { + hugo.Deprecate(".Sites.First", "Use .Sites.Default instead.", "v0.127.0") + return s.Default() +} + +// Default is a convenience method to get the site corresponding to the default +// content language. +func (s Sites) Default() Site { if len(s) == 0 { return nil } @@ -165,7 +172,7 @@ func (s *siteWrapper) Key() string { return s.s.Language().Lang } -// // Deprecated: Use .Site.Params instead. +// Deprecated: Use .Site.Params instead. func (s *siteWrapper) Social() map[string]string { return s.s.Social() } diff --git a/resources/page/site_integration_test.go b/resources/page/site_integration_test.go new file mode 100644 index 000000000..60064df3a --- /dev/null +++ b/resources/page/site_integration_test.go @@ -0,0 +1,44 @@ +// Copyright 2024 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 page_test + +import ( + "testing" + + "github.com/gohugoio/hugo/hugolib" +) + +// Issue 12513 +func TestPageSiteSitesDefault(t *testing.T) { + t.Parallel() + + files := ` +-- hugo.toml -- +disableKinds = ['page','rss','section','sitemap','taxonomy','term'] +defaultContentLanguage = 'de' +defaultContentLanguageInSubdir = true +[languages.en] +languageName = 'English' +weight = 1 +[languages.de] +languageName = 'Deutsch' +weight = 2 +-- layouts/index.html -- +{{ .Site.Sites.Default.Language.LanguageName }} +` + + b := hugolib.Test(t, files) + + b.AssertFileContent("public/de/index.html", "Deutsch") +} |