package render
import (
"html/template"
"net/url"
"path"
"strconv"
"strings"
)
const (
urlBasePublic = iota
urlBaseHTTP
urlBaseGemini
)
// URLBuilder is used to construct a URL for the site. The API of URLBuilder is
// designed to be convenient to used from a go template.
type URLBuilder struct {
publicURL, httpURL, geminiURL *url.URL
abs bool
base int
path, method string
page int
}
func NewURLBuilder(publicURL, httpURL, geminiURL *url.URL) URLBuilder {
return URLBuilder{
publicURL: publicURL,
httpURL: httpURL,
geminiURL: geminiURL,
}
}
func (b URLBuilder) String() string {
var u *url.URL
switch b.base {
case urlBasePublic:
u = b.publicURL
case urlBaseHTTP:
u = b.httpURL
case urlBaseGemini:
u = b.geminiURL
}
u = u.JoinPath(b.path)
if u.Scheme == "gemini" &&
u.Host == b.geminiURL.Host &&
!strings.HasSuffix(u.Path, "/") &&
path.Ext(u.Path) == "" {
u.Path += ".gmi"
}
{
query := url.Values{}
if b.method != "" {
query.Set("method", b.method)
}
if b.page > 0 {
query.Set("page", strconv.Itoa(b.page))
}
if len(query) > 0 {
u.RawQuery = query.Encode()
}
}
if abs := b.abs || u.Scheme != b.publicURL.Scheme; !abs {
u.Scheme = ""
u.Host = ""
}
return u.String()
}
func (b URLBuilder) HTMLSafe() template.URL {
return template.URL(b.String())
}
// Absolute returns a URLBuilder which will always construct a URL containing
// scheme and host.
func (b URLBuilder) Absolute() URLBuilder {
b.abs = true
return b
}
func (b URLBuilder) Gemini() URLBuilder {
b.base = urlBaseGemini
return b
}
func (b URLBuilder) HTTP() URLBuilder {
b.base = urlBaseHTTP
return b
}
func (b URLBuilder) Assets() URLBuilder {
b.path = "assets/"
return b
}
func (b URLBuilder) Asset(id string) URLBuilder {
b.path = "assets/" + id
return b
}
func (b URLBuilder) Posts() URLBuilder {
b.path = "posts/"
return b
}
func (b URLBuilder) Post(id string) URLBuilder {
b.path = "posts/" + id
return b
}
func (b URLBuilder) Drafts() URLBuilder {
b.base = urlBaseHTTP
b.path = "drafts/"
return b
}
func (b URLBuilder) Draft(id string) URLBuilder {
b.base = urlBaseHTTP
b.path = "drafts/" + id
return b
}
func (b URLBuilder) Static(staticPath string) URLBuilder {
b.base = urlBaseHTTP
b.path = path.Join("static", staticPath)
return b
}
func (b URLBuilder) Path(p string) URLBuilder {
b.path = p
return b
}
func (b URLBuilder) Page(page int) URLBuilder {
b.page = page
return b
}
func (b URLBuilder) MethodEdit() URLBuilder {
b.base = urlBaseHTTP
b.method = "edit"
return b
}
func (b URLBuilder) MethodManage() URLBuilder {
b.base = urlBaseHTTP
b.method = "manage"
return b
}
func (b URLBuilder) MethodDelete() URLBuilder {
b.base = urlBaseHTTP
b.method = "delete"
return b
}
func (b URLBuilder) MethodPreview() URLBuilder {
b.base = urlBaseHTTP
b.method = "preview"
return b
}