From 0665d0c65974533fbd313f4e0b062b5103057aeb Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Sat, 18 May 2024 18:29:19 +0200 Subject: Replace all URL rendering within templates by a URLConstructor --- src/render/url.go | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/render/url.go (limited to 'src/render/url.go') diff --git a/src/render/url.go b/src/render/url.go new file mode 100644 index 0000000..eb9756b --- /dev/null +++ b/src/render/url.go @@ -0,0 +1,168 @@ +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 +} -- cgit v1.2.3