shithub: hugo

Download patch

ref: 142558719324aa1628541d556ef1fa2d123f1e68
parent: a883948c4fa6d6de9ef2912709b42655c4cead83
author: Bjørn Erik Pedersen <[email protected]>
date: Tue Apr 4 14:14:41 EDT 2017

hugolib: Add optional outputFormat to Ref/RelRef

Fixes #3224

--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -1522,12 +1522,24 @@
 	return p.RSSLink()
 }
 
-func (p *Page) Ref(ref string) (string, error) {
-	return p.Site.Ref(ref, nil)
+func (p *Page) Ref(refs ...string) (string, error) {
+	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) {
-	return p.Site.RelRef(ref, nil)
+func (p *Page) RelRef(refs ...string) (string, error) {
+	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 {
--- a/hugolib/page_output.go
+++ b/hugolib/page_output.go
@@ -243,9 +243,8 @@
 // Get gets a OutputFormat given its name, i.e. json, html etc.
 // It returns nil if not found.
 func (o OutputFormats) Get(name string) *OutputFormat {
-	name = strings.ToLower(name)
 	for _, f := range o {
-		if strings.ToLower(f.f.Name) == name {
+		if strings.EqualFold(f.f.Name, name) {
 			return f
 		}
 	}
--- /dev/null
+++ b/hugolib/permalinker.go
@@ -1,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
+}
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -407,7 +407,7 @@
 	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 err error
 
@@ -433,10 +433,21 @@
 			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 {
-			link = target.RelPermalink()
+			link = permalinker.RelPermalink()
 		} else {
-			link = target.Permalink()
+			link = permalinker.Permalink()
 		}
 	}
 
@@ -454,13 +465,23 @@
 }
 
 // Ref will give an absolute URL to ref in the given Page.
-func (s *SiteInfo) Ref(ref string, page *Page) (string, error) {
-	return s.refLink(ref, page, false)
+func (s *SiteInfo) Ref(ref string, page *Page, options ...string) (string, error) {
+	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.
-func (s *SiteInfo) RelRef(ref string, page *Page) (string, error) {
-	return s.refLink(ref, page, true)
+func (s *SiteInfo) RelRef(ref string, page *Page, options ...string) (string, error) {
+	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
--- a/hugolib/site_test.go
+++ b/hugolib/site_test.go
@@ -894,10 +894,6 @@
 		{Name: filepath.FromSlash("level2/index.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/common.png"), Content: []byte("")},
 
@@ -912,12 +908,14 @@
 
 	cfg.Set("baseURL", "http://auth/")
 	cfg.Set("uglyURLs", false)
+	cfg.Set("outputs", map[string]interface{}{
+		"page": []string{"HTML", "AMP"},
+	})
 	cfg.Set("pluralizeListTitles", false)
 	cfg.Set("canonifyURLs", false)
 	cfg.Set("blackfriday",
 		map[string]interface{}{
 			"sourceRelativeLinksProjectFolder": "/docs"})
-
 	writeSourcesToSource(t, "content", fs, sources...)
 	return buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
 
@@ -932,19 +930,25 @@
 		t.Fatalf("failed to find current page in site")
 	}
 
-	// refLink doesn't use the location of the current page to work out reflinks
-	okresults := map[string]string{
+	for i, test := range []struct {
+		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.
 		// Before that, index.md would wrongly resolve to "/".
-		"index.md":  "/index/",
-		"common.md": "/level2/common/",
-		"3-root.md": "/level2/level3/3-root/",
-	}
-	for link, url := range okresults {
-		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)
+		{"index.md", "", true, "/index/"},
+		{"common.md", "", true, "/level2/common/"},
+		{"3-root.md", "", true, "/level2/level3/3-root/"},
+		{"index.md", "amp", true, "/amp/index/"},
+		{"index.md", "amp", false, "http://auth/amp/index/"},
+	} {
+		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.
 }
 
--- a/tpl/tplimpl/template_embedded.go
+++ b/tpl/tplimpl/template_embedded.go
@@ -14,8 +14,8 @@
 package tplimpl
 
 func (t *templateHandler) embedShortcodes() {
-	t.addInternalShortcode("ref.html", `{{ .Get 0 | ref .Page }}`)
-	t.addInternalShortcode("relref.html", `{{ .Get 0 | relref .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", `{{ 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("test.html", `This is a simple Test`)
 	t.addInternalShortcode("figure.html", `<!-- image -->
--- a/tpl/tplimpl/template_funcs.go
+++ b/tpl/tplimpl/template_funcs.go
@@ -46,7 +46,6 @@
 	"github.com/spf13/afero"
 	"github.com/spf13/cast"
 	"github.com/spf13/hugo/helpers"
-	jww "github.com/spf13/jwalterweatherman"
 
 	// Importing image codecs for image.DecodeConfig
 	_ "image/gif"
@@ -1432,41 +1431,30 @@
 	return helpers.StripHTML(s), nil
 }
 
-func refPage(page interface{}, ref, methodName string) template.HTML {
-	value := reflect.ValueOf(page)
-
-	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)
+type reflinker interface {
+	Ref(refs ...string) (string, error)
+	RelRef(refs ...string) (string, error)
 }
 
 // ref returns the absolute URL path to a given content item.
-func ref(page interface{}, ref string) template.HTML {
-	return refPage(page, ref, "Ref")
+func ref(in interface{}, refs ...string) (template.HTML, error) {
+	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.
-func relRef(page interface{}, ref string) template.HTML {
-	return refPage(page, ref, "RelRef")
+func relRef(in interface{}, refs ...string) (template.HTML, error) {
+	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.