A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

186 lines
4.2 KiB

  1. package writefreely
  2. import (
  3. "fmt"
  4. "github.com/dustin/go-humanize"
  5. "github.com/writeas/web-core/l10n"
  6. "github.com/writeas/web-core/log"
  7. "html/template"
  8. "io"
  9. "io/ioutil"
  10. "net/http"
  11. "os"
  12. "path/filepath"
  13. "strings"
  14. )
  15. var (
  16. templates = map[string]*template.Template{}
  17. pages = map[string]*template.Template{}
  18. userPages = map[string]*template.Template{}
  19. funcMap = template.FuncMap{
  20. "largeNumFmt": largeNumFmt,
  21. "pluralize": pluralize,
  22. "isRTL": isRTL,
  23. "isLTR": isLTR,
  24. "localstr": localStr,
  25. "localhtml": localHTML,
  26. "tolower": strings.ToLower,
  27. }
  28. )
  29. const (
  30. templatesDir = "templates/"
  31. pagesDir = "pages/"
  32. )
  33. func showUserPage(w http.ResponseWriter, name string, obj interface{}) {
  34. if obj == nil {
  35. log.Error("showUserPage: data is nil!")
  36. return
  37. }
  38. if err := userPages["user/"+name+".tmpl"].ExecuteTemplate(w, name, obj); err != nil {
  39. log.Error("Error parsing %s: %v", name, err)
  40. }
  41. }
  42. func initTemplate(name string) {
  43. if debugging {
  44. log.Info(" %s%s.tmpl", templatesDir, name)
  45. }
  46. if name == "collection" || name == "collection-tags" {
  47. // These pages list out collection posts, so we also parse templatesDir + "include/posts.tmpl"
  48. templates[name] = template.Must(template.New("").Funcs(funcMap).ParseFiles(
  49. templatesDir+name+".tmpl",
  50. templatesDir+"include/posts.tmpl",
  51. templatesDir+"include/footer.tmpl",
  52. templatesDir+"base.tmpl",
  53. ))
  54. } else {
  55. templates[name] = template.Must(template.New("").Funcs(funcMap).ParseFiles(
  56. templatesDir+name+".tmpl",
  57. templatesDir+"include/footer.tmpl",
  58. templatesDir+"base.tmpl",
  59. ))
  60. }
  61. }
  62. func initPage(path, key string) {
  63. if debugging {
  64. log.Info(" %s", key)
  65. }
  66. pages[key] = template.Must(template.New("").Funcs(funcMap).ParseFiles(
  67. path,
  68. templatesDir+"include/footer.tmpl",
  69. templatesDir+"base.tmpl",
  70. ))
  71. }
  72. func initUserPage(path, key string) {
  73. if debugging {
  74. log.Info(" %s", key)
  75. }
  76. userPages[key] = template.Must(template.New(key).Funcs(funcMap).ParseFiles(
  77. path,
  78. templatesDir+"user/include/header.tmpl",
  79. templatesDir+"user/include/footer.tmpl",
  80. ))
  81. }
  82. func initTemplates() error {
  83. log.Info("Loading templates...")
  84. tmplFiles, err := ioutil.ReadDir(templatesDir)
  85. if err != nil {
  86. return err
  87. }
  88. for _, f := range tmplFiles {
  89. if !f.IsDir() && !strings.HasPrefix(f.Name(), ".") {
  90. parts := strings.Split(f.Name(), ".")
  91. key := parts[0]
  92. initTemplate(key)
  93. }
  94. }
  95. log.Info("Loading pages...")
  96. // Initialize all static pages that use the base template
  97. filepath.Walk(pagesDir, func(path string, i os.FileInfo, err error) error {
  98. if !i.IsDir() && !strings.HasPrefix(i.Name(), ".") {
  99. parts := strings.Split(path, "/")
  100. key := i.Name()
  101. if len(parts) > 2 {
  102. key = fmt.Sprintf("%s/%s", parts[1], i.Name())
  103. }
  104. initPage(path, key)
  105. }
  106. return nil
  107. })
  108. log.Info("Loading user pages...")
  109. // Initialize all user pages that use base templates
  110. filepath.Walk(templatesDir+"/user/", func(path string, f os.FileInfo, err error) error {
  111. if !f.IsDir() && !strings.HasPrefix(f.Name(), ".") {
  112. parts := strings.Split(path, "/")
  113. key := f.Name()
  114. if len(parts) > 2 {
  115. key = fmt.Sprintf("%s/%s", parts[1], f.Name())
  116. }
  117. initUserPage(path, key)
  118. }
  119. return nil
  120. })
  121. return nil
  122. }
  123. // renderPage retrieves the given template and renders it to the given io.Writer.
  124. // If something goes wrong, the error is logged and returned.
  125. func renderPage(w io.Writer, tmpl string, data interface{}) error {
  126. err := pages[tmpl].ExecuteTemplate(w, "base", data)
  127. if err != nil {
  128. log.Error("%v", err)
  129. }
  130. return err
  131. }
  132. func largeNumFmt(n int64) string {
  133. return humanize.Comma(n)
  134. }
  135. func pluralize(singular, plural string, n int64) string {
  136. if n == 1 {
  137. return singular
  138. }
  139. return plural
  140. }
  141. func isRTL(d string) bool {
  142. return d == "rtl"
  143. }
  144. func isLTR(d string) bool {
  145. return d == "ltr" || d == "auto"
  146. }
  147. func localStr(term, lang string) string {
  148. s := l10n.Strings(lang)[term]
  149. if s == "" {
  150. s = l10n.Strings("")[term]
  151. }
  152. return s
  153. }
  154. func localHTML(term, lang string) template.HTML {
  155. s := l10n.Strings(lang)[term]
  156. if s == "" {
  157. s = l10n.Strings("")[term]
  158. }
  159. s = strings.Replace(s, "write.as", "<a href=\"https://writefreely.org\">write freely</a>", 1)
  160. return template.HTML(s)
  161. }