github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/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 provides template functions to deal with URLs.
    15  package urls
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"html/template"
    21  	"net/url"
    22  
    23  	"github.com/gohugoio/hugo/common/urls"
    24  	"github.com/gohugoio/hugo/deps"
    25  	_errors "github.com/pkg/errors"
    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, _errors.Wrap(err, "Error in Parse")
    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 ns.deps.ContentSpec.SanitizeAnchorName(s), nil
    91  }
    92  
    93  // Ref returns the absolute URL path to a given content item.
    94  func (ns *Namespace) Ref(in interface{}, args interface{}) (template.HTML, error) {
    95  	p, ok := in.(urls.RefLinker)
    96  	if !ok {
    97  		return "", errors.New("invalid Page received in Ref")
    98  	}
    99  	argsm, err := ns.refArgsToMap(args)
   100  	if err != nil {
   101  		return "", err
   102  	}
   103  	s, err := p.Ref(argsm)
   104  	return template.HTML(s), err
   105  }
   106  
   107  // RelRef returns the relative URL path to a given content item.
   108  func (ns *Namespace) RelRef(in interface{}, args interface{}) (template.HTML, error) {
   109  	p, ok := in.(urls.RefLinker)
   110  	if !ok {
   111  		return "", errors.New("invalid Page received in RelRef")
   112  	}
   113  	argsm, err := ns.refArgsToMap(args)
   114  	if err != nil {
   115  		return "", err
   116  	}
   117  
   118  	s, err := p.RelRef(argsm)
   119  	return template.HTML(s), err
   120  }
   121  
   122  func (ns *Namespace) refArgsToMap(args interface{}) (map[string]interface{}, error) {
   123  	var (
   124  		s  string
   125  		of string
   126  	)
   127  
   128  	v := args
   129  	if _, ok := v.([]interface{}); ok {
   130  		v = cast.ToStringSlice(v)
   131  	}
   132  
   133  	switch v := v.(type) {
   134  	case map[string]interface{}:
   135  		return v, nil
   136  	case map[string]string:
   137  		m := make(map[string]interface{})
   138  		for k, v := range v {
   139  			m[k] = v
   140  		}
   141  		return m, nil
   142  	case []string:
   143  		if len(v) == 0 || len(v) > 2 {
   144  			return nil, fmt.Errorf("invalid number of arguments to ref")
   145  		}
   146  		// These where the options before we introduced the map type:
   147  		s = v[0]
   148  		if len(v) == 2 {
   149  			of = v[1]
   150  		}
   151  	default:
   152  		var err error
   153  		s, err = cast.ToStringE(args)
   154  		if err != nil {
   155  			return nil, err
   156  		}
   157  
   158  	}
   159  
   160  	return map[string]interface{}{
   161  		"path":         s,
   162  		"outputFormat": of,
   163  	}, nil
   164  }
   165  
   166  // RelLangURL takes a given string and prepends the relative path according to a
   167  // page's position in the project directory structure and the current language.
   168  func (ns *Namespace) RelLangURL(a interface{}) (template.HTML, error) {
   169  	s, err := cast.ToStringE(a)
   170  	if err != nil {
   171  		return "", err
   172  	}
   173  
   174  	return template.HTML(ns.deps.PathSpec.RelURL(s, !ns.multihost)), nil
   175  }
   176  
   177  // AbsLangURL takes a given string and converts it to an absolute URL according
   178  // to a page's position in the project directory structure and the current
   179  // language.
   180  func (ns *Namespace) AbsLangURL(a interface{}) (template.HTML, error) {
   181  	s, err := cast.ToStringE(a)
   182  	if err != nil {
   183  		return "", err
   184  	}
   185  
   186  	return template.HTML(ns.deps.PathSpec.AbsURL(s, !ns.multihost)), nil
   187  }