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 }