github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/resources/page/page.go (about)

     1  // Copyright 2019 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // Package page contains the core interfaces and types for the Page resource,
    15  // a core component in Hugo.
    16  package page
    17  
    18  import (
    19  	"context"
    20  	"html/template"
    21  
    22  	"github.com/gohugoio/hugo/identity"
    23  	"github.com/gohugoio/hugo/markup/converter"
    24  	"github.com/gohugoio/hugo/markup/tableofcontents"
    25  
    26  	"github.com/gohugoio/hugo/config"
    27  	"github.com/gohugoio/hugo/tpl"
    28  
    29  	"github.com/gohugoio/hugo/common/maps"
    30  	"github.com/gohugoio/hugo/compare"
    31  	"github.com/gohugoio/hugo/hugofs/files"
    32  
    33  	"github.com/gohugoio/hugo/navigation"
    34  	"github.com/gohugoio/hugo/related"
    35  	"github.com/gohugoio/hugo/resources/resource"
    36  	"github.com/gohugoio/hugo/source"
    37  )
    38  
    39  // Clear clears any global package state.
    40  func Clear() error {
    41  	spc.clear()
    42  	return nil
    43  }
    44  
    45  // AlternativeOutputFormatsProvider provides alternative output formats for a
    46  // Page.
    47  type AlternativeOutputFormatsProvider interface {
    48  	// AlternativeOutputFormats gives the alternative output formats for the
    49  	// current output.
    50  	// Note that we use the term "alternative" and not "alternate" here, as it
    51  	// does not necessarily replace the other format, it is an alternative representation.
    52  	AlternativeOutputFormats() OutputFormats
    53  }
    54  
    55  // AuthorProvider provides author information.
    56  type AuthorProvider interface {
    57  	// Deprecated.
    58  	Author() Author
    59  	// Deprecated.
    60  	Authors() AuthorList
    61  }
    62  
    63  // ChildCareProvider provides accessors to child resources.
    64  type ChildCareProvider interface {
    65  	// Pages returns a list of pages of all kinds.
    66  	Pages() Pages
    67  
    68  	// RegularPages returns a list of pages of kind 'Page'.
    69  	RegularPages() Pages
    70  
    71  	// RegularPagesRecursive returns all regular pages below the current
    72  	// section.
    73  	RegularPagesRecursive() Pages
    74  
    75  	// Resources returns a list of all resources.
    76  	Resources() resource.Resources
    77  }
    78  
    79  // ContentProvider provides the content related values for a Page.
    80  type ContentProvider interface {
    81  	Content(context.Context) (any, error)
    82  
    83  	// Plain returns the Page Content stripped of HTML markup.
    84  	Plain(context.Context) string
    85  
    86  	// PlainWords returns a string slice from splitting Plain using https://pkg.go.dev/strings#Fields.
    87  	PlainWords(context.Context) []string
    88  
    89  	// Summary returns a generated summary of the content.
    90  	// The breakpoint can be set manually by inserting a summary separator in the source file.
    91  	Summary(context.Context) template.HTML
    92  
    93  	// Truncated returns whether the Summary  is truncated or not.
    94  	Truncated(context.Context) bool
    95  
    96  	// FuzzyWordCount returns the approximate number of words in the content.
    97  	FuzzyWordCount(context.Context) int
    98  
    99  	// WordCount returns the number of words in the content.
   100  	WordCount(context.Context) int
   101  
   102  	// ReadingTime returns the reading time based on the length of plain text.
   103  	ReadingTime(context.Context) int
   104  
   105  	// Len returns the length of the content.
   106  	// This is for internal use only.
   107  	Len(context.Context) int
   108  }
   109  
   110  // ContentRenderer provides the content rendering methods for some content.
   111  type ContentRenderer interface {
   112  	// ParseAndRenderContent renders the given content.
   113  	// For internal use only.
   114  	ParseAndRenderContent(ctx context.Context, content []byte, enableTOC bool) (converter.ResultRender, error)
   115  	// For internal use only.
   116  	ParseContent(ctx context.Context, content []byte) (converter.ResultParse, bool, error)
   117  	// For internal use only.
   118  	RenderContent(ctx context.Context, content []byte, doc any) (converter.ResultRender, bool, error)
   119  }
   120  
   121  // FileProvider provides the source file.
   122  type FileProvider interface {
   123  	// File returns the source file for this Page,
   124  	// or a zero File if this Page is not backed by a file.
   125  	File() source.File
   126  }
   127  
   128  // GetPageProvider provides the GetPage method.
   129  type GetPageProvider interface {
   130  	// GetPage looks up a page for the given ref.
   131  	//    {{ with .GetPage "blog" }}{{ .Title }}{{ end }}
   132  	//
   133  	// This will return nil when no page could be found, and will return
   134  	// an error if the ref is ambiguous.
   135  	GetPage(ref string) (Page, error)
   136  
   137  	// GetPageWithTemplateInfo is for internal use only.
   138  	GetPageWithTemplateInfo(info tpl.Info, ref string) (Page, error)
   139  }
   140  
   141  // GitInfoProvider provides Git info.
   142  type GitInfoProvider interface {
   143  	// GitInfo returns the Git info for this object.
   144  	GitInfo() source.GitInfo
   145  	// CodeOwners returns the code owners for this object.
   146  	CodeOwners() []string
   147  }
   148  
   149  // InSectionPositioner provides section navigation.
   150  type InSectionPositioner interface {
   151  	// NextInSection returns the next page in the same section.
   152  	NextInSection() Page
   153  	// PrevInSection returns the previous page in the same section.
   154  	PrevInSection() Page
   155  }
   156  
   157  // InternalDependencies is considered an internal interface.
   158  type InternalDependencies interface {
   159  	// GetRelatedDocsHandler is for internal use only.
   160  	GetRelatedDocsHandler() *RelatedDocsHandler
   161  }
   162  
   163  // OutputFormatsProvider provides the OutputFormats of a Page.
   164  type OutputFormatsProvider interface {
   165  	// OutputFormats returns the OutputFormats for this Page.
   166  	OutputFormats() OutputFormats
   167  }
   168  
   169  // Page is the core interface in Hugo.
   170  type Page interface {
   171  	ContentProvider
   172  	TableOfContentsProvider
   173  	PageWithoutContent
   174  }
   175  
   176  type PageFragment interface {
   177  	resource.ResourceLinksProvider
   178  	resource.ResourceMetaProvider
   179  }
   180  
   181  // PageMetaProvider provides page metadata, typically provided via front matter.
   182  type PageMetaProvider interface {
   183  	// The 4 page dates
   184  	resource.Dated
   185  
   186  	// Aliases forms the base for redirects generation.
   187  	Aliases() []string
   188  
   189  	// BundleType returns the bundle type: `leaf`, `branch` or an empty string.
   190  	BundleType() files.ContentClass
   191  
   192  	// A configured description.
   193  	Description() string
   194  
   195  	// Whether this is a draft. Will only be true if run with the --buildDrafts (-D) flag.
   196  	Draft() bool
   197  
   198  	// IsHome returns whether this is the home page.
   199  	IsHome() bool
   200  
   201  	// Configured keywords.
   202  	Keywords() []string
   203  
   204  	// The Page Kind. One of page, home, section, taxonomy, term.
   205  	Kind() string
   206  
   207  	// The configured layout to use to render this page. Typically set in front matter.
   208  	Layout() string
   209  
   210  	// The title used for links.
   211  	LinkTitle() string
   212  
   213  	// IsNode returns whether this is an item of one of the list types in Hugo,
   214  	// i.e. not a regular content
   215  	IsNode() bool
   216  
   217  	// IsPage returns whether this is a regular content
   218  	IsPage() bool
   219  
   220  	// Param looks for a param in Page and then in Site config.
   221  	Param(key any) (any, error)
   222  
   223  	// Path gets the relative path, including file name and extension if relevant,
   224  	// to the source of this Page. It will be relative to any content root.
   225  	Path() string
   226  
   227  	// This is just a temporary bridge method. Use Path in templates.
   228  	// Pathc is for internal usage only.
   229  	Pathc() string
   230  
   231  	// The slug, typically defined in front matter.
   232  	Slug() string
   233  
   234  	// This page's language code. Will be the same as the site's.
   235  	Lang() string
   236  
   237  	// IsSection returns whether this is a section
   238  	IsSection() bool
   239  
   240  	// Section returns the first path element below the content root.
   241  	Section() string
   242  
   243  	// Returns a slice of sections (directories if it's a file) to this
   244  	// Page.
   245  	SectionsEntries() []string
   246  
   247  	// SectionsPath is SectionsEntries joined with a /.
   248  	SectionsPath() string
   249  
   250  	// Sitemap returns the sitemap configuration for this page.
   251  	// This is for internal use only.
   252  	Sitemap() config.Sitemap
   253  
   254  	// Type is a discriminator used to select layouts etc. It is typically set
   255  	// in front matter, but will fall back to the root section.
   256  	Type() string
   257  
   258  	// The configured weight, used as the first sort value in the default
   259  	// page sort if non-zero.
   260  	Weight() int
   261  }
   262  
   263  // PageRenderProvider provides a way for a Page to render content.
   264  type PageRenderProvider interface {
   265  	// Render renders the given layout with this Page as context.
   266  	Render(ctx context.Context, layout ...string) (template.HTML, error)
   267  	// RenderString renders the first value in args with tPaginatorhe content renderer defined
   268  	// for this Page.
   269  	// It takes an optional map as a second argument:
   270  	//
   271  	// display (“inline”):
   272  	// - inline or block. If inline (default), surrounding <p></p> on short snippets will be trimmed.
   273  	// markup (defaults to the Page’s markup)
   274  	RenderString(ctx context.Context, args ...any) (template.HTML, error)
   275  }
   276  
   277  // PageWithoutContent is the Page without any of the content methods.
   278  type PageWithoutContent interface {
   279  	RawContentProvider
   280  	resource.Resource
   281  	PageMetaProvider
   282  	resource.LanguageProvider
   283  
   284  	// For pages backed by a file.
   285  	FileProvider
   286  
   287  	GitInfoProvider
   288  
   289  	// Output formats
   290  	OutputFormatsProvider
   291  	AlternativeOutputFormatsProvider
   292  
   293  	// Tree navigation
   294  	ChildCareProvider
   295  	TreeProvider
   296  
   297  	// Horizontal navigation
   298  	InSectionPositioner
   299  	PageRenderProvider
   300  	PaginatorProvider
   301  	Positioner
   302  	navigation.PageMenusProvider
   303  
   304  	// TODO(bep)
   305  	AuthorProvider
   306  
   307  	// Page lookups/refs
   308  	GetPageProvider
   309  	RefProvider
   310  
   311  	resource.TranslationKeyProvider
   312  	TranslationsProvider
   313  
   314  	SitesProvider
   315  
   316  	// Helper methods
   317  	ShortcodeInfoProvider
   318  	compare.Eqer
   319  
   320  	// Scratch returns a Scratch that can be used to store temporary state.
   321  	// Note that this Scratch gets reset on server rebuilds. See Store() for a variant that survives.
   322  	maps.Scratcher
   323  
   324  	// Store returns a Scratch that can be used to store temporary state.
   325  	// In contrast to Scratch(), this Scratch is not reset on server rebuilds.
   326  	Store() *maps.Scratch
   327  
   328  	RelatedKeywordsProvider
   329  
   330  	// GetTerms gets the terms of a given taxonomy,
   331  	// e.g. GetTerms("categories")
   332  	GetTerms(taxonomy string) Pages
   333  
   334  	// Used in change/dependency tracking.
   335  	identity.Provider
   336  
   337  	// Headings returns the headings for this page when a filter is set.
   338  	// This is currently only triggered with the Related content feature
   339  	// and the "fragments" type of index.
   340  	HeadingsFiltered(context.Context) tableofcontents.Headings
   341  
   342  	DeprecatedWarningPageMethods
   343  }
   344  
   345  // Positioner provides next/prev navigation.
   346  type Positioner interface {
   347  	// Next points up to the next regular page (sorted by Hugo’s default sort).
   348  	Next() Page
   349  	// Prev points down to the previous regular page (sorted by Hugo’s default sort).
   350  	Prev() Page
   351  
   352  	// Deprecated: Use Prev. Will be removed in Hugo 0.57
   353  	PrevPage() Page
   354  
   355  	// Deprecated: Use Next. Will be removed in Hugo 0.57
   356  	NextPage() Page
   357  }
   358  
   359  // RawContentProvider provides the raw, unprocessed content of the page.
   360  type RawContentProvider interface {
   361  	// RawContent returns the raw, unprocessed content of the page excluding any front matter.
   362  	RawContent() string
   363  }
   364  
   365  // RefProvider provides the methods needed to create reflinks to pages.
   366  type RefProvider interface {
   367  	// Ref returns an absolute URl to a page.
   368  	Ref(argsm map[string]any) (string, error)
   369  
   370  	// RefFrom is for internal use only.
   371  	RefFrom(argsm map[string]any, source any) (string, error)
   372  
   373  	// RelRef returns a relative URL to a page.
   374  	RelRef(argsm map[string]any) (string, error)
   375  
   376  	// RefFrom is for internal use only.
   377  	RelRefFrom(argsm map[string]any, source any) (string, error)
   378  }
   379  
   380  // RelatedKeywordsProvider allows a Page to be indexed.
   381  type RelatedKeywordsProvider interface {
   382  	// Make it indexable as a related.Document
   383  	// RelatedKeywords is meant for internal usage only.
   384  	RelatedKeywords(cfg related.IndexConfig) ([]related.Keyword, error)
   385  }
   386  
   387  // ShortcodeInfoProvider provides info about the shortcodes in a Page.
   388  type ShortcodeInfoProvider interface {
   389  	// HasShortcode return whether the page has a shortcode with the given name.
   390  	// This method is mainly motivated with the Hugo Docs site's need for a list
   391  	// of pages with the `todo` shortcode in it.
   392  	HasShortcode(name string) bool
   393  }
   394  
   395  // SitesProvider provide accessors to get sites.
   396  type SitesProvider interface {
   397  	// Site returns the current site.
   398  	Site() Site
   399  	// Sites returns all sites.
   400  	Sites() Sites
   401  }
   402  
   403  // TableOfContentsProvider provides the table of contents for a Page.
   404  type TableOfContentsProvider interface {
   405  	// TableOfContents returns the table of contents for the page rendered as HTML.
   406  	TableOfContents(context.Context) template.HTML
   407  
   408  	// Fragments returns the fragments for this page.
   409  	Fragments(context.Context) *tableofcontents.Fragments
   410  }
   411  
   412  // TranslationsProvider provides access to any translations.
   413  type TranslationsProvider interface {
   414  
   415  	// IsTranslated returns whether this content file is translated to
   416  	// other language(s).
   417  	IsTranslated() bool
   418  
   419  	// AllTranslations returns all translations, including the current Page.
   420  	AllTranslations() Pages
   421  
   422  	// Translations returns the translations excluding the current Page.
   423  	Translations() Pages
   424  }
   425  
   426  // TreeProvider provides section tree navigation.
   427  type TreeProvider interface {
   428  
   429  	// IsAncestor returns whether the current page is an ancestor of other.
   430  	// Note that this method is not relevant for taxonomy lists and taxonomy terms pages.
   431  	IsAncestor(other any) (bool, error)
   432  
   433  	// CurrentSection returns the page's current section or the page itself if home or a section.
   434  	// Note that this will return nil for pages that is not regular, home or section pages.
   435  	CurrentSection() Page
   436  
   437  	// IsDescendant returns whether the current page is a descendant of other.
   438  	// Note that this method is not relevant for taxonomy lists and taxonomy terms pages.
   439  	IsDescendant(other any) (bool, error)
   440  
   441  	// FirstSection returns the section on level 1 below home, e.g. "/docs".
   442  	// For the home page, this will return itself.
   443  	FirstSection() Page
   444  
   445  	// InSection returns whether other is in the current section.
   446  	// Note that this will always return false for pages that are
   447  	// not either regular, home or section pages.
   448  	InSection(other any) (bool, error)
   449  
   450  	// Parent returns a section's parent section or a page's section.
   451  	// To get a section's subsections, see Page's Sections method.
   452  	Parent() Page
   453  
   454  	// Ancestors returns the ancestors of each page
   455  	Ancestors() Pages
   456  
   457  	// Sections returns this section's subsections, if any.
   458  	// Note that for non-sections, this method will always return an empty list.
   459  	Sections() Pages
   460  
   461  	// Page returns a reference to the Page itself, kept here mostly
   462  	// for legacy reasons.
   463  	Page() Page
   464  }
   465  
   466  // DeprecatedWarningPageMethods lists deprecated Page methods that will trigger
   467  // a WARNING if invoked.
   468  // This was added in Hugo 0.55.
   469  type DeprecatedWarningPageMethods any // This was emptied in Hugo 0.93.0.
   470  
   471  // Move here to trigger ERROR instead of WARNING.
   472  // TODO(bep) create wrappers and put into the Page once it has some methods.
   473  type DeprecatedErrorPageMethods any
   474  
   475  // PageWithContext is a Page with a context.Context.
   476  type PageWithContext struct {
   477  	Page
   478  	Ctx context.Context
   479  }
   480  
   481  func (p PageWithContext) Content() (any, error) {
   482  	return p.Page.Content(p.Ctx)
   483  }
   484  
   485  func (p PageWithContext) Plain() string {
   486  	return p.Page.Plain(p.Ctx)
   487  }
   488  
   489  func (p PageWithContext) PlainWords() []string {
   490  	return p.Page.PlainWords(p.Ctx)
   491  }
   492  
   493  func (p PageWithContext) Summary() template.HTML {
   494  	return p.Page.Summary(p.Ctx)
   495  }
   496  
   497  func (p PageWithContext) Truncated() bool {
   498  	return p.Page.Truncated(p.Ctx)
   499  }
   500  
   501  func (p PageWithContext) FuzzyWordCount() int {
   502  	return p.Page.FuzzyWordCount(p.Ctx)
   503  }
   504  
   505  func (p PageWithContext) WordCount() int {
   506  	return p.Page.WordCount(p.Ctx)
   507  }
   508  
   509  func (p PageWithContext) ReadingTime() int {
   510  	return p.Page.ReadingTime(p.Ctx)
   511  }
   512  
   513  func (p PageWithContext) Len() int {
   514  	return p.Page.Len(p.Ctx)
   515  }