Skip to content

Commit

Permalink
Refactor flawed custom static page implementation.
Browse files Browse the repository at this point in the history
- Remove incorrect global compilation of site theme files + pages.
- Compile each page separately with a clone of the theme templates
  and maintain a map.
  • Loading branch information
knadh committed Nov 27, 2023
1 parent 2d54982 commit 9515c55
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 44 deletions.
16 changes: 10 additions & 6 deletions cmd/dictpress/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,12 @@ type Consts struct {
// App contains the "global" components that are
// passed around, especially through HTTP handlers.
type App struct {
consts Consts
adminTpl *template.Template
siteTpl *template.Template
consts Consts

adminTpl *template.Template
siteTpl *template.Template
sitePageTpls map[string]*template.Template

db *sqlx.DB
queries *data.Queries
data *data.Data
Expand Down Expand Up @@ -205,7 +208,7 @@ func main() {
// Load optional HTML website.
if app.consts.Site != "" {
lo.Printf("loading site theme: %s", app.consts.Site)
t, err := loadSite(app.consts.Site, ko.Bool("app.enable_pages"))
theme, pages, err := loadSite(app.consts.Site, ko.Bool("app.enable_pages"))
if err != nil {
lo.Fatalf("error loading site theme: %v", err)
}
Expand All @@ -223,8 +226,9 @@ func main() {
}

// Attach HTML template renderer.
app.siteTpl = t
srv.Renderer = &tplRenderer{tpls: t}
app.siteTpl = theme
app.sitePageTpls = pages
srv.Renderer = &tplRenderer{tpls: theme}
}

lo.Printf("starting server on %s", ko.MustString("app.address"))
Expand Down
94 changes: 74 additions & 20 deletions cmd/dictpress/site.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package main

import (
"bytes"
"crypto/md5"
"fmt"
"html/template"
"io"
"net/http"
"net/url"
"path"
"path/filepath"
"strings"
"time"

Expand All @@ -25,7 +28,9 @@ const (
)

type pageTpl struct {
PageName string
PageType string
PageID string

Title string
Heading string
Description string
Expand Down Expand Up @@ -72,7 +77,7 @@ func init() {
// handleIndexPage renders the homepage.
func handleIndexPage(c echo.Context) error {
return c.Render(http.StatusOK, "index", pageTpl{
PageName: pageIndex,
PageType: pageIndex,
})
}

Expand All @@ -88,7 +93,7 @@ func handleSearchPage(c echo.Context) error {
}

return c.Render(http.StatusOK, "search", pageTpl{
PageName: pageSearch,
PageType: pageSearch,
Results: res,
Query: &query,
})
Expand Down Expand Up @@ -142,7 +147,7 @@ func handleGlossaryPage(c echo.Context) error {
if len(initials) == 0 {
// No glossary initials found.
return c.Render(http.StatusOK, "glossary", pageTpl{
PageName: pageGlossary,
PageType: pageGlossary,
Initial: initial,
})
}
Expand Down Expand Up @@ -174,7 +179,7 @@ func handleGlossaryPage(c echo.Context) error {

// Render the results.
return c.Render(http.StatusOK, "glossary", pageTpl{
PageName: pageGlossary,
PageType: pageGlossary,
Initial: initial,
Initials: initials,
Glossary: gloss,
Expand All @@ -187,49 +192,98 @@ func handleGlossaryPage(c echo.Context) error {
func handleStaticPage(c echo.Context) error {
var (
app = c.Get("app").(*App)
id = "page-" + strings.TrimRight(c.Param("page"), "/")
id = strings.TrimRight(c.Param("page"), "/")
)

if app.siteTpl.Lookup(id) == nil {
tpl, ok := app.sitePageTpls[id]
if !ok {
return c.Render(http.StatusNotFound, "message", pageTpl{
Title: "404",
Heading: "Page not found",
})
}

return c.Render(http.StatusOK, id, pageTpl{
PageName: pageStatic,
})
// Render the body.
b := bytes.Buffer{}

if err := tpl.ExecuteTemplate(&b, "page-"+id, tplData{
Path: c.Path(),
AssetVer: assetVer,
Consts: app.consts,
Langs: app.data.Langs,
Dicts: app.data.Dicts,
L: app.i18n,
Data: pageTpl{
PageType: pageStatic,
PageID: id,
},
}); err != nil {
return err
}

return c.HTMLBlob(http.StatusOK, b.Bytes())
}

// loadSite loads HTML site theme templates.
func loadSite(path string, loadPages bool) (*template.Template, error) {
t := template.New("site").Funcs(sprig.FuncMap())
// loadSite loads HTML site theme templates and any additional pages (in the `pages/` dir)
// in a map indexed by the page's template name in {{ define "page-$name" }}.
func loadSite(rootPath string, loadPages bool) (*template.Template, map[string]*template.Template, error) {
theme := template.New("site").Funcs(sprig.FuncMap())

// Go percentage encodes unicode characters printed in <a href>,
// but the encoded values are in lowercase hex (for some reason)
// See: https://github.com/golang/go/issues/33596
t.Funcs(template.FuncMap{"UnicodeURL": func(s string) template.URL {
theme.Funcs(template.FuncMap{"UnicodeURL": func(s string) template.URL {
s = strings.ReplaceAll(s, " ", "+")
return template.URL(url.PathEscape(s))
}})

if _, err := t.ParseGlob(path + "/*.html"); err != nil {
return t, err
if _, err := theme.ParseGlob(rootPath + "/*.html"); err != nil {
return nil, nil, err
}

// Load arbitrary pages from (site_dir/pages/*.html).
// For instance, "about" for site_dir/pages/about.html will be
// rendered on site.com/pages/about where the template is defined
// with the name {{ define "page-about" }}. All template name definitions
// should be "page-*".
if loadPages {
if _, err := t.ParseGlob(path + "/pages/*.html"); err != nil {
return t, err
if !loadPages {
return theme, nil, nil
}

pages := make(map[string]*template.Template)
files, err := filepath.Glob(path.Join(rootPath, "/pages", "*.html"))
if err != nil {
return nil, nil, err
}

// Iterate through all *.html files in the given directory
for _, file := range files {
copy, err := theme.Clone()
if err != nil {
return nil, nil, err
}

t, err := copy.ParseFiles(file)
if err != nil {
return nil, nil, err
}

// Get the name of individual templates ({{ define "page-$name" }}.
name := ""
for _, t := range t.Templates() {
if t.Tree != nil && strings.HasPrefix(t.Tree.Name, "page-") {
name = strings.TrimPrefix(t.Tree.Name, "page-")
if old, ok := pages[name]; ok {
return nil, nil, fmt.Errorf("template '%s' in %s already defined in %s", t.Tree.Name, t.Name(), old.Name())
}
break
}
}

pages[name] = t
}

return t, nil
return theme, pages, nil
}

// Render executes and renders a template for echo.
Expand Down
35 changes: 19 additions & 16 deletions site/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,32 @@
<html>
<head>
<meta charset="utf-8" />
<title>
{{- if eq .Data.PageName "/" }} {{- .L.T "global.siteName" -}}
{{- else if eq .Data.PageName "glossary" }}{{- .L.T "public.glossaryTitle" -}}
{{- else if eq .Data.PageName "search" }}{{- .L.Ts "public.searchTitle" "query" .Data.Query.Query -}}
{{- else if ne .Data.Title "" }}{{ .Data.Title }}
{{- else }}{{ block "title" . }}{{end}}
{{- end -}}
</title>
<meta name="description" value="
{{- if eq .Data.PageName "/" }}Dictionary website
{{- else if eq .Data.PageName "glossary" }}Glossary of words.
{{- else if eq .Data.PageName "search" }}{{ .Data.Query.Query }} meaning.
{{- else if ne .Data.Description "" }}{{ .Data.Description }}
{{- else }}{{ block "description" . }}{{end}}
{{- end -}}" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

{{- block "meta" . -}}
<title>
{{- if eq .Data.PageType "/" }} {{- .L.T "global.siteName" -}}
{{- else if eq .Data.PageType "glossary" }}{{- .L.T "public.glossaryTitle" -}}
{{- else if eq .Data.PageType "search" }}{{- .L.Ts "public.searchTitle" "query" .Data.Query.Query -}}
{{- else if ne .Data.Title "" }}{{ .Data.Title }}
{{- end -}}
</title>
<meta name="description" value="
{{- if eq .Data.PageType "/" }}Dictionary website
{{- else if eq .Data.PageType "glossary" }}Glossary of words.
{{- else if eq .Data.PageType "search" }}{{ .Data.Query.Query }} meaning.
{{- else if ne .Data.Description "" }}{{ .Data.Description }}
{{- else }}{{ block "description" . }}{{end}}
{{- end -}}" />
{{- end -}}

<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<script>window._ROOT_URL = "{{ .Consts.RootURL }}";</script>
<link rel="shortcut icon" href="{{ .Consts.RootURL }}/static/favicon.png?v={{ .AssetVer }}" type="image/x-icon" />
<link href="{{ .Consts.RootURL }}/static/flexit.css?v={{ .AssetVer }}" rel="stylesheet" type="text/css" />
<link href="{{ .Consts.RootURL }}/static/style.css?v={{ .AssetVer }}" rel="stylesheet" type="text/css" />
</head>
<body class="{{ if eq .Data.PageName "/"}}home{{ end }}">
<body class="{{ if eq .Data.PageType "/"}}home{{ end }}">
<div class="wrap">
<section class="container main box">
<header class="header">
Expand Down
6 changes: 4 additions & 2 deletions site/pages/about.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{{ define "title" }}About this site{{ end }}
{{ define "description" }}About this site{{ end }}
{{ define "meta" }}
<title>About this site</title>
{{ end }}

{{ define "page-about" }}
{{ template "header" . }}
<section class="content about">
Expand Down

0 comments on commit 9515c55

Please sign in to comment.