mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
a883948c4f
commit
1425587193
7 changed files with 108 additions and 59 deletions
|
@ -1522,12 +1522,24 @@ func (p *Page) RSSlink() template.URL {
|
||||||
return p.RSSLink()
|
return p.RSSLink()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Page) Ref(ref string) (string, error) {
|
func (p *Page) Ref(refs ...string) (string, error) {
|
||||||
return p.Site.Ref(ref, nil)
|
if len(refs) == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if len(refs) > 1 {
|
||||||
|
return p.Site.Ref(refs[0], nil, refs[1])
|
||||||
|
}
|
||||||
|
return p.Site.Ref(refs[0], nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Page) RelRef(ref string) (string, error) {
|
func (p *Page) RelRef(refs ...string) (string, error) {
|
||||||
return p.Site.RelRef(ref, nil)
|
if len(refs) == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if len(refs) > 1 {
|
||||||
|
return p.Site.RelRef(refs[0], nil, refs[1])
|
||||||
|
}
|
||||||
|
return p.Site.RelRef(refs[0], nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Page) String() string {
|
func (p *Page) String() string {
|
||||||
|
|
|
@ -243,9 +243,8 @@ func (p *Page) AlternativeOutputFormats() (OutputFormats, error) {
|
||||||
// Get gets a OutputFormat given its name, i.e. json, html etc.
|
// Get gets a OutputFormat given its name, i.e. json, html etc.
|
||||||
// It returns nil if not found.
|
// It returns nil if not found.
|
||||||
func (o OutputFormats) Get(name string) *OutputFormat {
|
func (o OutputFormats) Get(name string) *OutputFormat {
|
||||||
name = strings.ToLower(name)
|
|
||||||
for _, f := range o {
|
for _, f := range o {
|
||||||
if strings.ToLower(f.f.Name) == name {
|
if strings.EqualFold(f.f.Name, name) {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
25
hugolib/permalinker.go
Normal file
25
hugolib/permalinker.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2017-present 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 hugolib
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ Permalinker = (*Page)(nil)
|
||||||
|
_ Permalinker = (*OutputFormat)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Permalinker provides permalinks of both the relative and absolute kind.
|
||||||
|
type Permalinker interface {
|
||||||
|
Permalink() string
|
||||||
|
RelPermalink() string
|
||||||
|
}
|
|
@ -407,7 +407,7 @@ func (s *SiteInfo) IsMultiLingual() bool {
|
||||||
return len(s.Languages) > 1
|
return len(s.Languages) > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SiteInfo) refLink(ref string, page *Page, relative bool) (string, error) {
|
func (s *SiteInfo) refLink(ref string, page *Page, relative bool, outputFormat string) (string, error) {
|
||||||
var refURL *url.URL
|
var refURL *url.URL
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -433,10 +433,21 @@ func (s *SiteInfo) refLink(ref string, page *Page, relative bool) (string, error
|
||||||
return "", fmt.Errorf("No page found with path or logical name \"%s\".\n", refURL.Path)
|
return "", fmt.Errorf("No page found with path or logical name \"%s\".\n", refURL.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var permalinker Permalinker = target
|
||||||
|
|
||||||
|
if outputFormat != "" {
|
||||||
|
o := target.OutputFormats().Get(outputFormat)
|
||||||
|
|
||||||
|
if o == nil {
|
||||||
|
return "", fmt.Errorf("Output format %q not found for page %q", outputFormat, refURL.Path)
|
||||||
|
}
|
||||||
|
permalinker = o
|
||||||
|
}
|
||||||
|
|
||||||
if relative {
|
if relative {
|
||||||
link = target.RelPermalink()
|
link = permalinker.RelPermalink()
|
||||||
} else {
|
} else {
|
||||||
link = target.Permalink()
|
link = permalinker.Permalink()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,13 +465,23 @@ func (s *SiteInfo) refLink(ref string, page *Page, relative bool) (string, error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ref will give an absolute URL to ref in the given Page.
|
// Ref will give an absolute URL to ref in the given Page.
|
||||||
func (s *SiteInfo) Ref(ref string, page *Page) (string, error) {
|
func (s *SiteInfo) Ref(ref string, page *Page, options ...string) (string, error) {
|
||||||
return s.refLink(ref, page, false)
|
outputFormat := ""
|
||||||
|
if len(options) > 0 {
|
||||||
|
outputFormat = options[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.refLink(ref, page, false, outputFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RelRef will give an relative URL to ref in the given Page.
|
// RelRef will give an relative URL to ref in the given Page.
|
||||||
func (s *SiteInfo) RelRef(ref string, page *Page) (string, error) {
|
func (s *SiteInfo) RelRef(ref string, page *Page, options ...string) (string, error) {
|
||||||
return s.refLink(ref, page, true)
|
outputFormat := ""
|
||||||
|
if len(options) > 0 {
|
||||||
|
outputFormat = options[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.refLink(ref, page, true, outputFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SourceRelativeLink attempts to convert any source page relative links (like [../another.md]) into absolute links
|
// SourceRelativeLink attempts to convert any source page relative links (like [../another.md]) into absolute links
|
||||||
|
|
|
@ -894,10 +894,6 @@ func setupLinkingMockSite(t *testing.T) *Site {
|
||||||
{Name: filepath.FromSlash("level2/index.md"), Content: []byte("")},
|
{Name: filepath.FromSlash("level2/index.md"), Content: []byte("")},
|
||||||
{Name: filepath.FromSlash("level2/common.md"), Content: []byte("")},
|
{Name: filepath.FromSlash("level2/common.md"), Content: []byte("")},
|
||||||
|
|
||||||
// {Name: filepath.FromSlash("level2b/2b-root.md"), Content: []byte("")},
|
|
||||||
// {Name: filepath.FromSlash("level2b/index.md"), Content: []byte("")},
|
|
||||||
// {Name: filepath.FromSlash("level2b/common.md"), Content: []byte("")},
|
|
||||||
|
|
||||||
{Name: filepath.FromSlash("level2/2-image.png"), Content: []byte("")},
|
{Name: filepath.FromSlash("level2/2-image.png"), Content: []byte("")},
|
||||||
{Name: filepath.FromSlash("level2/common.png"), Content: []byte("")},
|
{Name: filepath.FromSlash("level2/common.png"), Content: []byte("")},
|
||||||
|
|
||||||
|
@ -912,12 +908,14 @@ func setupLinkingMockSite(t *testing.T) *Site {
|
||||||
|
|
||||||
cfg.Set("baseURL", "http://auth/")
|
cfg.Set("baseURL", "http://auth/")
|
||||||
cfg.Set("uglyURLs", false)
|
cfg.Set("uglyURLs", false)
|
||||||
|
cfg.Set("outputs", map[string]interface{}{
|
||||||
|
"page": []string{"HTML", "AMP"},
|
||||||
|
})
|
||||||
cfg.Set("pluralizeListTitles", false)
|
cfg.Set("pluralizeListTitles", false)
|
||||||
cfg.Set("canonifyURLs", false)
|
cfg.Set("canonifyURLs", false)
|
||||||
cfg.Set("blackfriday",
|
cfg.Set("blackfriday",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"sourceRelativeLinksProjectFolder": "/docs"})
|
"sourceRelativeLinksProjectFolder": "/docs"})
|
||||||
|
|
||||||
writeSourcesToSource(t, "content", fs, sources...)
|
writeSourcesToSource(t, "content", fs, sources...)
|
||||||
return buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
|
return buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
|
||||||
|
|
||||||
|
@ -932,19 +930,25 @@ func TestRefLinking(t *testing.T) {
|
||||||
t.Fatalf("failed to find current page in site")
|
t.Fatalf("failed to find current page in site")
|
||||||
}
|
}
|
||||||
|
|
||||||
// refLink doesn't use the location of the current page to work out reflinks
|
for i, test := range []struct {
|
||||||
okresults := map[string]string{
|
link string
|
||||||
|
outputFormat string
|
||||||
|
relative bool
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
// Note: There are no magic in the index.md name. This was fixed in Hugo 0.20.
|
// Note: There are no magic in the index.md name. This was fixed in Hugo 0.20.
|
||||||
// Before that, index.md would wrongly resolve to "/".
|
// Before that, index.md would wrongly resolve to "/".
|
||||||
"index.md": "/index/",
|
{"index.md", "", true, "/index/"},
|
||||||
"common.md": "/level2/common/",
|
{"common.md", "", true, "/level2/common/"},
|
||||||
"3-root.md": "/level2/level3/3-root/",
|
{"3-root.md", "", true, "/level2/level3/3-root/"},
|
||||||
}
|
{"index.md", "amp", true, "/amp/index/"},
|
||||||
for link, url := range okresults {
|
{"index.md", "amp", false, "http://auth/amp/index/"},
|
||||||
if out, err := site.Info.refLink(link, currentPage, true); err != nil || out != url {
|
} {
|
||||||
t.Errorf("Expected %s to resolve to (%s), got (%s) - error: %s", link, url, out, err)
|
if out, err := site.Info.refLink(test.link, currentPage, test.relative, test.outputFormat); err != nil || out != test.expected {
|
||||||
|
t.Errorf("[%d] Expected %s to resolve to (%s), got (%s) - error: %s", i, test.link, test.expected, out, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: and then the failure cases.
|
// TODO: and then the failure cases.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
package tplimpl
|
package tplimpl
|
||||||
|
|
||||||
func (t *templateHandler) embedShortcodes() {
|
func (t *templateHandler) embedShortcodes() {
|
||||||
t.addInternalShortcode("ref.html", `{{ .Get 0 | ref .Page }}`)
|
t.addInternalShortcode("ref.html", `{{ if len .Params | eq 2 }}{{ ref .Page (.Get 0) (.Get 1) }}{{ else }}{{ ref .Page (.Get 0) }}{{ end }}`)
|
||||||
t.addInternalShortcode("relref.html", `{{ .Get 0 | relref .Page }}`)
|
t.addInternalShortcode("relref.html", `{{ if len .Params | eq 2 }}{{ relref .Page (.Get 0) (.Get 1) }}{{ else }}{{ relref .Page (.Get 0) }}{{ end }}`)
|
||||||
t.addInternalShortcode("highlight.html", `{{ if len .Params | eq 2 }}{{ highlight .Inner (.Get 0) (.Get 1) }}{{ else }}{{ highlight .Inner (.Get 0) "" }}{{ end }}`)
|
t.addInternalShortcode("highlight.html", `{{ if len .Params | eq 2 }}{{ highlight .Inner (.Get 0) (.Get 1) }}{{ else }}{{ highlight .Inner (.Get 0) "" }}{{ end }}`)
|
||||||
t.addInternalShortcode("test.html", `This is a simple Test`)
|
t.addInternalShortcode("test.html", `This is a simple Test`)
|
||||||
t.addInternalShortcode("figure.html", `<!-- image -->
|
t.addInternalShortcode("figure.html", `<!-- image -->
|
||||||
|
|
|
@ -46,7 +46,6 @@ import (
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
"github.com/spf13/hugo/helpers"
|
"github.com/spf13/hugo/helpers"
|
||||||
jww "github.com/spf13/jwalterweatherman"
|
|
||||||
|
|
||||||
// Importing image codecs for image.DecodeConfig
|
// Importing image codecs for image.DecodeConfig
|
||||||
_ "image/gif"
|
_ "image/gif"
|
||||||
|
@ -1432,41 +1431,30 @@ func plainify(in interface{}) (string, error) {
|
||||||
return helpers.StripHTML(s), nil
|
return helpers.StripHTML(s), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func refPage(page interface{}, ref, methodName string) template.HTML {
|
type reflinker interface {
|
||||||
value := reflect.ValueOf(page)
|
Ref(refs ...string) (string, error)
|
||||||
|
RelRef(refs ...string) (string, error)
|
||||||
method := value.MethodByName(methodName)
|
|
||||||
|
|
||||||
if method.IsValid() && method.Type().NumIn() == 1 && method.Type().NumOut() == 2 {
|
|
||||||
result := method.Call([]reflect.Value{reflect.ValueOf(ref)})
|
|
||||||
|
|
||||||
url, err := result[0], result[1]
|
|
||||||
|
|
||||||
if !err.IsNil() {
|
|
||||||
jww.ERROR.Printf("%s", err.Interface())
|
|
||||||
return template.HTML(fmt.Sprintf("%s", err.Interface()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if url.String() == "" {
|
|
||||||
jww.ERROR.Printf("ref %s could not be found\n", ref)
|
|
||||||
return template.HTML(ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
return template.HTML(url.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
jww.ERROR.Printf("Can only create references from Page and Node objects.")
|
|
||||||
return template.HTML(ref)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ref returns the absolute URL path to a given content item.
|
// ref returns the absolute URL path to a given content item.
|
||||||
func ref(page interface{}, ref string) template.HTML {
|
func ref(in interface{}, refs ...string) (template.HTML, error) {
|
||||||
return refPage(page, ref, "Ref")
|
p, ok := in.(reflinker)
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("invalid Page received in ref")
|
||||||
|
}
|
||||||
|
s, err := p.Ref(refs...)
|
||||||
|
return template.HTML(s), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// relRef returns the relative URL path to a given content item.
|
// relRef returns the relative URL path to a given content item.
|
||||||
func relRef(page interface{}, ref string) template.HTML {
|
func relRef(in interface{}, refs ...string) (template.HTML, error) {
|
||||||
return refPage(page, ref, "RelRef")
|
p, ok := in.(reflinker)
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("invalid Page received in relref")
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := p.RelRef(refs...)
|
||||||
|
return template.HTML(s), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// chomp removes trailing newline characters from a string.
|
// chomp removes trailing newline characters from a string.
|
||||||
|
|
Loading…
Reference in a new issue