shithub: hugo

Download patch

ref: d741064bebe2f4663a7ba12556dccc3dffe08629
parent: 3eb313fef495a39731dafa6bddbf77760090230d
author: Bjørn Erik Pedersen <[email protected]>
date: Tue Jul 17 17:44:08 EDT 2018

Add optional lang as argument to rel/relref

Fixes #4956

--- a/hugolib/language_content_dir_test.go
+++ b/hugolib/language_content_dir_test.go
@@ -81,6 +81,9 @@
 
 Content.
 
+SVP3-REF: {{< ref path="/sect/page3.md" lang="sv" >}}
+SVP3-RELREF: {{< relref path="/sect/page3.md" lang="sv" >}}
+
 `
 
 	pageBundleTemplate := `
@@ -211,24 +214,32 @@
 	assert.NoError(err)
 	nnP2, err := nnSite.getPageNew(nil, "/sect/page2.md")
 	assert.NoError(err)
-	nnP2_2, err := svSite.getPageNew(nil, "/nn/sect/page2.md")
-	assert.NoError(err)
-	enP2_2, err := nnSite.getPageNew(nil, "/en/sect/page2.md")
-	assert.NoError(err)
-	svP2_2, err := enSite.getPageNew(nil, "/sv/sect/page2.md")
-	assert.NoError(err)
 
 	enP2, err := enSite.getPageNew(nil, "/sect/page2.md")
 	assert.NoError(err)
-	assert.NotNil(enP2)
-	assert.NotNil(svP2)
-	assert.NotNil(nnP2)
+	assert.Equal("en", enP2.Lang())
 	assert.Equal("sv", svP2.Lang())
 	assert.Equal("nn", nnP2.Lang())
-	assert.Equal("en", enP2.Lang())
-	assert.Equal(nnP2, nnP2_2)
-	assert.Equal(enP2, enP2_2)
-	assert.Equal(svP2, svP2_2)
+
+	content, _ := nnP2.Content()
+	assert.Contains(content, "SVP3-REF: https://example.org/sv/sect/p-sv-3/")
+	assert.Contains(content, "SVP3-RELREF: /sv/sect/p-sv-3/")
+
+	// Test RelRef with and without language indicator.
+	nn3RefArgs := map[string]interface{}{
+		"path": "/sect/page3.md",
+		"lang": "nn",
+	}
+	nnP3RelRef, err := svP2.RelRef(
+		nn3RefArgs,
+	)
+	assert.NoError(err)
+	assert.Equal("/nn/sect/p-nn-3/", nnP3RelRef)
+	nnP3Ref, err := svP2.Ref(
+		nn3RefArgs,
+	)
+	assert.NoError(err)
+	assert.Equal("https://example.org/nn/sect/p-nn-3/", nnP3Ref)
 
 	for i, p := range enSite.RegularPages {
 		j := i + 1
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -2038,24 +2038,68 @@
 	return p.s.getPageNew(p, ref)
 }
 
-func (p *Page) Ref(refs ...string) (string, error) {
-	if len(refs) == 0 {
+type refArgs struct {
+	Path         string
+	Lang         string
+	OutputFormat string
+}
+
+func (p *Page) decodeRefArgs(args map[string]interface{}) (refArgs, *SiteInfo, error) {
+	var ra refArgs
+	err := mapstructure.WeakDecode(args, &ra)
+	if err != nil {
+		return ra, nil, nil
+	}
+	s := p.Site
+
+	if ra.Lang != "" && ra.Lang != p.Lang() {
+		// Find correct site
+		found := false
+		for _, ss := range p.s.owner.Sites {
+			if ss.Lang() == ra.Lang {
+				found = true
+				s = &ss.Info
+			}
+		}
+
+		if !found {
+			return ra, nil, fmt.Errorf("no site found with lang %q", ra.Lang)
+		}
+	}
+
+	return ra, s, nil
+}
+
+func (p *Page) Ref(argsm map[string]interface{}) (string, error) {
+	args, s, err := p.decodeRefArgs(argsm)
+	if err != nil {
+		return "", fmt.Errorf("invalid arguments to Ref: %s", err)
+	}
+
+	if args.Path == "" {
 		return "", nil
 	}
-	if len(refs) > 1 {
-		return p.Site.Ref(refs[0], p, refs[1])
+
+	if args.OutputFormat != "" {
+		return s.Ref(args.Path, p, args.OutputFormat)
 	}
-	return p.Site.Ref(refs[0], p)
+	return s.Ref(args.Path, p)
 }
 
-func (p *Page) RelRef(refs ...string) (string, error) {
-	if len(refs) == 0 {
+func (p *Page) RelRef(argsm map[string]interface{}) (string, error) {
+	args, s, err := p.decodeRefArgs(argsm)
+	if err != nil {
+		return "", fmt.Errorf("invalid arguments to Ref: %s", err)
+	}
+
+	if args.Path == "" {
 		return "", nil
 	}
-	if len(refs) > 1 {
-		return p.Site.RelRef(refs[0], p, refs[1])
+
+	if args.OutputFormat != "" {
+		return s.RelRef(args.Path, p, args.OutputFormat)
 	}
-	return p.Site.RelRef(refs[0], p)
+	return s.RelRef(args.Path, p)
 }
 
 func (p *Page) String() string {
--- a/hugolib/page_collections.go
+++ b/hugolib/page_collections.go
@@ -76,12 +76,6 @@
 	c.RegularPages = c.findPagesByKindIn(KindPage, c.Pages)
 	c.AllRegularPages = c.findPagesByKindIn(KindPage, c.AllPages)
 
-	var s *Site
-
-	if len(c.Pages) > 0 {
-		s = c.Pages[0].s
-	}
-
 	indexLoader := func() (map[string]interface{}, error) {
 		index := make(map[string]interface{})
 
@@ -94,44 +88,34 @@
 			}
 		}
 
-		// Note that we deliberately use the pages from all sites
-		// in this index, as we intend to use this in the ref and relref
-		// shortcodes.
-		for _, pageCollection := range []Pages{c.AllRegularPages, c.headlessPages} {
+		for _, pageCollection := range []Pages{c.RegularPages, c.headlessPages} {
 			for _, p := range pageCollection {
 				sourceRef := p.absoluteSourceRef()
 
-				// Allow cross language references by
-				// adding the language code as prefix.
-				add(path.Join("/"+p.Lang(), sourceRef), p)
+				if sourceRef != "" {
+					// index the canonical ref
+					// e.g. /section/article.md
+					add(sourceRef, p)
+				}
 
-				// For pages in the current language.
-				if s != nil && p.s == s {
-					if sourceRef != "" {
-						// index the canonical ref
-						// e.g. /section/article.md
-						add(sourceRef, p)
-					}
+				// Ref/Relref supports this potentially ambiguous lookup.
+				add(p.Source.LogicalName(), p)
 
-					// Ref/Relref supports this potentially ambiguous lookup.
-					add(p.Source.LogicalName(), p)
+				translationBaseName := p.Source.TranslationBaseName()
 
-					translationBaseName := p.Source.TranslationBaseName()
+				dir, _ := path.Split(sourceRef)
+				dir = strings.TrimSuffix(dir, "/")
 
-					dir, _ := path.Split(sourceRef)
-					dir = strings.TrimSuffix(dir, "/")
-
-					if translationBaseName == "index" {
-						add(dir, p)
-						add(path.Base(dir), p)
-					} else {
-						add(translationBaseName, p)
-					}
-
-					// We need a way to get to the current language version.
-					pathWithNoExtensions := path.Join(dir, translationBaseName)
-					add(pathWithNoExtensions, p)
+				if translationBaseName == "index" {
+					add(dir, p)
+					add(path.Base(dir), p)
+				} else {
+					add(translationBaseName, p)
 				}
+
+				// We need a way to get to the current language version.
+				pathWithNoExtensions := path.Join(dir, translationBaseName)
+				add(pathWithNoExtensions, p)
 			}
 		}
 
--- a/hugolib/shortcode.go
+++ b/hugolib/shortcode.go
@@ -55,13 +55,13 @@
 }
 
 // Ref is a shortcut to the Ref method on Page.
-func (scp *ShortcodeWithPage) Ref(ref string) (string, error) {
-	return scp.Page.Ref(ref)
+func (scp *ShortcodeWithPage) Ref(args map[string]interface{}) (string, error) {
+	return scp.Page.Ref(args)
 }
 
 // RelRef is a shortcut to the RelRef method on Page.
-func (scp *ShortcodeWithPage) RelRef(ref string) (string, error) {
-	return scp.Page.RelRef(ref)
+func (scp *ShortcodeWithPage) RelRef(args map[string]interface{}) (string, error) {
+	return scp.Page.RelRef(args)
 }
 
 // Scratch returns a scratch-pad scoped for this shortcode. This can be used
--- a/tpl/tplimpl/embedded/templates.autogen.go
+++ b/tpl/tplimpl/embedded/templates.autogen.go
@@ -380,8 +380,8 @@
 </style>
 {{ end }}
 {{ end }}`},
-	{`shortcodes/ref.html`, `{{ if len .Params | eq 2 }}{{ ref .Page (.Get 0) (.Get 1) }}{{ else }}{{ ref .Page (.Get 0) }}{{ end }}`},
-	{`shortcodes/relref.html`, `{{ if len .Params | eq 2 }}{{ relref .Page (.Get 0) (.Get 1) }}{{ else }}{{ relref .Page (.Get 0) }}{{ end }}`},
+	{`shortcodes/ref.html`, `{{ ref .Page .Params }}`},
+	{`shortcodes/relref.html`, `{{ relref .Page .Params }}`},
 	{`shortcodes/twitter.html`, `{{- $pc := .Page.Site.Config.Privacy.Twitter -}}
 {{- if not $pc.Disable -}}
 {{- if $pc.Simple -}}
--- a/tpl/tplimpl/embedded/templates/shortcodes/ref.html
+++ b/tpl/tplimpl/embedded/templates/shortcodes/ref.html
@@ -1,1 +1,1 @@
-{{ if len .Params | eq 2 }}{{ ref .Page (.Get 0) (.Get 1) }}{{ else }}{{ ref .Page (.Get 0) }}{{ end }}
\ No newline at end of file
+{{ ref .Page .Params }}
\ No newline at end of file
--- a/tpl/tplimpl/embedded/templates/shortcodes/relref.html
+++ b/tpl/tplimpl/embedded/templates/shortcodes/relref.html
@@ -1,1 +1,1 @@
-{{ if len .Params | eq 2 }}{{ relref .Page (.Get 0) (.Get 1) }}{{ else }}{{ relref .Page (.Get 0) }}{{ end }}
\ No newline at end of file
+{{ relref .Page .Params }}
\ No newline at end of file
--- a/tpl/urls/urls.go
+++ b/tpl/urls/urls.go
@@ -91,28 +91,74 @@
 }
 
 type reflinker interface {
-	Ref(refs ...string) (string, error)
-	RelRef(refs ...string) (string, error)
+	Ref(args map[string]interface{}) (string, error)
+	RelRef(args map[string]interface{}) (string, error)
 }
 
 // Ref returns the absolute URL path to a given content item.
-func (ns *Namespace) Ref(in interface{}, refs ...string) (template.HTML, error) {
+func (ns *Namespace) Ref(in interface{}, args interface{}) (template.HTML, error) {
 	p, ok := in.(reflinker)
 	if !ok {
 		return "", errors.New("invalid Page received in Ref")
 	}
-	s, err := p.Ref(refs...)
+	argsm, err := ns.refArgsToMap(args)
+	if err != nil {
+		return "", err
+	}
+	s, err := p.Ref(argsm)
 	return template.HTML(s), err
 }
 
 // RelRef returns the relative URL path to a given content item.
-func (ns *Namespace) RelRef(in interface{}, refs ...string) (template.HTML, error) {
+func (ns *Namespace) RelRef(in interface{}, args interface{}) (template.HTML, error) {
 	p, ok := in.(reflinker)
 	if !ok {
 		return "", errors.New("invalid Page received in RelRef")
 	}
-	s, err := p.RelRef(refs...)
+	argsm, err := ns.refArgsToMap(args)
+	if err != nil {
+		return "", err
+	}
+
+	s, err := p.RelRef(argsm)
 	return template.HTML(s), err
+}
+
+func (ns *Namespace) refArgsToMap(args interface{}) (map[string]interface{}, error) {
+	var (
+		s  string
+		of string
+	)
+	switch v := args.(type) {
+	case map[string]interface{}:
+		return v, nil
+	case map[string]string:
+		m := make(map[string]interface{})
+		for k, v := range v {
+			m[k] = v
+		}
+		return m, nil
+	case []string:
+		if len(v) == 0 || len(v) > 2 {
+			return nil, fmt.Errorf("invalid numer of arguments to ref")
+		}
+		// These where the options before we introduced the map type:
+		s = v[0]
+		if len(v) == 2 {
+			of = v[1]
+		}
+	default:
+		var err error
+		s, err = cast.ToStringE(args)
+		if err != nil {
+			return nil, err
+		}
+
+	}
+	return map[string]interface{}{
+		"path":         s,
+		"outputFormat": of,
+	}, nil
 }
 
 // RelLangURL takes a given string and prepends the relative path according to a