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 }