github.com/lyeb/hugo@v0.47.1/tpl/urls/urls.go (about)

     1  // Copyright 2017 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 urls
    15  
    16  import (
    17  	"errors"
    18  	"fmt"
    19  
    20  	"github.com/russross/blackfriday"
    21  
    22  	"html/template"
    23  	"net/url"
    24  
    25  	"github.com/gohugoio/hugo/deps"
    26  	"github.com/spf13/cast"
    27  )
    28  
    29  // New returns a new instance of the urls-namespaced template functions.
    30  func New(deps *deps.Deps) *Namespace {
    31  	return &Namespace{
    32  		deps:      deps,
    33  		multihost: deps.Cfg.GetBool("multihost"),
    34  	}
    35  }
    36  
    37  // Namespace provides template functions for the "urls" namespace.
    38  type Namespace struct {
    39  	deps      *deps.Deps
    40  	multihost bool
    41  }
    42  
    43  // AbsURL takes a given string and converts it to an absolute URL.
    44  func (ns *Namespace) AbsURL(a interface{}) (template.HTML, error) {
    45  	s, err := cast.ToStringE(a)
    46  	if err != nil {
    47  		return "", nil
    48  	}
    49  
    50  	return template.HTML(ns.deps.PathSpec.AbsURL(s, false)), nil
    51  }
    52  
    53  // Parse parses rawurl into a URL structure. The rawurl may be relative or
    54  // absolute.
    55  func (ns *Namespace) Parse(rawurl interface{}) (*url.URL, error) {
    56  	s, err := cast.ToStringE(rawurl)
    57  	if err != nil {
    58  		return nil, fmt.Errorf("Error in Parse: %s", err)
    59  	}
    60  
    61  	return url.Parse(s)
    62  }
    63  
    64  // RelURL takes a given string and prepends the relative path according to a
    65  // page's position in the project directory structure.
    66  func (ns *Namespace) RelURL(a interface{}) (template.HTML, error) {
    67  	s, err := cast.ToStringE(a)
    68  	if err != nil {
    69  		return "", nil
    70  	}
    71  
    72  	return template.HTML(ns.deps.PathSpec.RelURL(s, false)), nil
    73  }
    74  
    75  // URLize returns the given argument formatted as URL.
    76  func (ns *Namespace) URLize(a interface{}) (string, error) {
    77  	s, err := cast.ToStringE(a)
    78  	if err != nil {
    79  		return "", nil
    80  	}
    81  	return ns.deps.PathSpec.URLize(s), nil
    82  }
    83  
    84  // Anchorize creates sanitized anchor names that are compatible with Blackfriday.
    85  func (ns *Namespace) Anchorize(a interface{}) (string, error) {
    86  	s, err := cast.ToStringE(a)
    87  	if err != nil {
    88  		return "", nil
    89  	}
    90  	return blackfriday.SanitizedAnchorName(s), nil
    91  }
    92  
    93  type reflinker interface {
    94  	Ref(args map[string]interface{}) (string, error)
    95  	RelRef(args map[string]interface{}) (string, error)
    96  }
    97  
    98  // Ref returns the absolute URL path to a given content item.
    99  func (ns *Namespace) Ref(in interface{}, args interface{}) (template.HTML, error) {
   100  	p, ok := in.(reflinker)
   101  	if !ok {
   102  		return "", errors.New("invalid Page received in Ref")
   103  	}
   104  	argsm, err := ns.refArgsToMap(args)
   105  	if err != nil {
   106  		return "", err
   107  	}
   108  	s, err := p.Ref(argsm)
   109  	return template.HTML(s), err
   110  }
   111  
   112  // RelRef returns the relative URL path to a given content item.
   113  func (ns *Namespace) RelRef(in interface{}, args interface{}) (template.HTML, error) {
   114  	p, ok := in.(reflinker)
   115  	if !ok {
   116  		return "", errors.New("invalid Page received in RelRef")
   117  	}
   118  	argsm, err := ns.refArgsToMap(args)
   119  	if err != nil {
   120  		return "", err
   121  	}
   122  
   123  	s, err := p.RelRef(argsm)
   124  	return template.HTML(s), err
   125  }
   126  
   127  func (ns *Namespace) refArgsToMap(args interface{}) (map[string]interface{}, error) {
   128  	var (
   129  		s  string
   130  		of string
   131  	)
   132  	switch v := args.(type) {
   133  	case map[string]interface{}:
   134  		return v, nil
   135  	case map[string]string:
   136  		m := make(map[string]interface{})
   137  		for k, v := range v {
   138  			m[k] = v
   139  		}
   140  		return m, nil
   141  	case []string:
   142  		if len(v) == 0 || len(v) > 2 {
   143  			return nil, fmt.Errorf("invalid numer of arguments to ref")
   144  		}
   145  		// These where the options before we introduced the map type:
   146  		s = v[0]
   147  		if len(v) == 2 {
   148  			of = v[1]
   149  		}
   150  	default:
   151  		var err error
   152  		s, err = cast.ToStringE(args)
   153  		if err != nil {
   154  			return nil, err
   155  		}
   156  
   157  	}
   158  	return map[string]interface{}{
   159  		"path":         s,
   160  		"outputFormat": of,
   161  	}, nil
   162  }
   163  
   164  // RelLangURL takes a given string and prepends the relative path according to a
   165  // page's position in the project directory structure and the current language.
   166  func (ns *Namespace) RelLangURL(a interface{}) (template.HTML, error) {
   167  	s, err := cast.ToStringE(a)
   168  	if err != nil {
   169  		return "", err
   170  	}
   171  
   172  	return template.HTML(ns.deps.PathSpec.RelURL(s, !ns.multihost)), nil
   173  }
   174  
   175  // AbsLangURL takes a given string and converts it to an absolute URL according
   176  // to a page's position in the project directory structure and the current
   177  // language.
   178  func (ns *Namespace) AbsLangURL(a interface{}) (template.HTML, error) {
   179  	s, err := cast.ToStringE(a)
   180  	if err != nil {
   181  		return "", err
   182  	}
   183  
   184  	return template.HTML(ns.deps.PathSpec.AbsURL(s, !ns.multihost)), nil
   185  }