diff --git a/controllers/listcontroller.go b/controllers/listcontroller.go
index ad59367..447f4c9 100644
--- a/controllers/listcontroller.go
+++ b/controllers/listcontroller.go
@@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
"strings"
+ "time"
"git.aiterp.net/gisle/wrouter/response"
@@ -24,10 +25,10 @@ func listIndex(path string, w http.ResponseWriter, req *http.Request, user *auth
return false
}
- vm := viewmodel.PageList{}
+ vm := viewmodel.IndexList{}
vm.Headers, err = model.ListHeaders()
vm.Categories = model.PageCategories
- vm.Setup(user)
+ vm.Setup(user, req.URL.Path, "Index")
if err != nil {
response.Text(w, 500, err.Error())
@@ -49,7 +50,7 @@ func listFiltered(category model.PageCategory) wrouter.FunctionHandlerFunc {
tagName := strings.Replace(req.URL.Path[len(path):], "_", " ", -1)
- vm := viewmodel.PageList{}
+ vm := viewmodel.IndexList{}
if tagName != "" {
tag, err := model.FindTag("name", tagName, "")
@@ -66,7 +67,7 @@ func listFiltered(category model.PageCategory) wrouter.FunctionHandlerFunc {
vm.Categories = model.PageCategories
vm.ActiveCategory = category
- vm.Setup(user)
+ vm.Setup(user, path, category.Plural)
if err != nil {
response.Text(w, 500, err.Error())
@@ -89,7 +90,7 @@ func listTagged(tagType string) wrouter.FunctionHandlerFunc {
tagName := strings.Replace(req.URL.Path[len(path):], "_", " ", -1)
- vm := viewmodel.PageList{}
+ vm := viewmodel.IndexList{}
if tagName == "" {
return false
@@ -105,7 +106,7 @@ func listTagged(tagType string) wrouter.FunctionHandlerFunc {
vm.Headers, err = model.ListHeadersByTag("", tag)
vm.Categories = model.PageCategories
- vm.Setup(user)
+ vm.Setup(user, tag.Path(), tag.Name)
if err != nil {
response.Text(w, 500, err.Error())
@@ -118,11 +119,90 @@ func listTagged(tagType string) wrouter.FunctionHandlerFunc {
}
}
+func tagList(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
+ //var err error
+ if (req.Method != "GET" && req.Method != "POST") || len(req.URL.Path) > len(path) {
+ return false
+ }
+
+ tl := viewmodel.IndexTags{}
+ tl.Tags, _ = model.ListTags()
+ tl.Setup(user, path)
+
+ view.Render(w, "tags", 200, tl)
+
+ return true
+}
+
+func listAuthor(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
+ var err error
+
+ if req.Method != "GET" || strings.LastIndex(req.URL.Path, "/") >= len(path) {
+ return false
+ }
+
+ authorName := strings.Replace(req.URL.Path[len(path):], "_", " ", -1)
+
+ vm := viewmodel.IndexList{}
+ vm.ActiveAuthor = authorName
+
+ vm.Headers, err = model.ListHeadersByAuthor(authorName)
+ if err != nil {
+ response.Text(w, 500, err.Error())
+ return true
+ }
+
+ if len(vm.Headers) > 0 {
+ authorName = vm.Headers[0].Author
+ }
+
+ vm.Categories = model.PageCategories
+ vm.Setup(user, "/author/"+authorName, authorName)
+
+ view.Render(w, "index", 200, vm)
+
+ return true
+}
+
+func listDate(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
+ var err error
+
+ if req.Method != "GET" || strings.LastIndex(req.URL.Path, "/") >= len(path) {
+ return false
+ }
+
+ date, err := time.Parse("2006-01", req.URL.Path[len(path):])
+ if err != nil {
+ response.Text(w, 400, "Invalid date")
+ return true
+ }
+
+ vm := viewmodel.IndexList{}
+ vm.ActiveDate = date.Format("January 2006")
+ vm.ActiveDatePath = "/month/" + date.Format("2006-01")
+
+ vm.Headers, err = model.ListHeadersByMonth(date.Year(), int(date.Month()))
+ if err != nil {
+ response.Text(w, 500, err.Error())
+ return true
+ }
+
+ vm.Categories = model.PageCategories
+ vm.Setup(user, "/month/"+date.Format("2006-01"), vm.ActiveDate)
+
+ view.Render(w, "index", 200, vm)
+
+ return true
+}
+
func init() {
ListController.Function("/", listIndex)
+ ListController.Function("/tags/", tagList)
+ ListController.Function("/author/", listAuthor)
+ ListController.Function("/month/", listDate)
for _, category := range model.PageCategories {
- ListController.Function(fmt.Sprintf("/%s/", strings.ToLower(category.Plural)), listFiltered(category))
+ ListController.Function(category.Path, listFiltered(category))
}
for _, tagType := range model.TagTypes {
diff --git a/controllers/pagecontroller.go b/controllers/pagecontroller.go
index efb5c6f..78d08f6 100644
--- a/controllers/pagecontroller.go
+++ b/controllers/pagecontroller.go
@@ -25,9 +25,8 @@ func pageCreate(path string, w http.ResponseWriter, req *http.Request, user *aut
return false
}
- pc := viewmodel.PageForm{}
+ pc := viewmodel.PageCreate{}
pc.Setup(user)
- pc.Operation = "Create"
// Make sure the user is logged in
if user == nil {
@@ -110,7 +109,7 @@ func pageCreate(path string, w http.ResponseWriter, req *http.Request, user *aut
pc.TagInput = req.Form.Get("tags")
}
- view.Render(w, "page/create", 200, pc)
+ view.Render(w, "create", 200, pc)
return true
}
@@ -137,6 +136,28 @@ func pageView(path string, w http.ResponseWriter, req *http.Request, user *auth.
return true
}
+func pageSource(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
+ if req.Method != "GET" || strings.LastIndex(req.URL.Path, "/") > len(path) {
+ return false
+ }
+
+ page, err := model.FindPage(req.URL.Path[len(path):])
+ if err != nil {
+ response.Text(w, 500, err.Error())
+ return true
+ } else if page == nil {
+ return false
+ }
+
+ pv := viewmodel.PageSource{}
+ pv.Page = page
+ pv.Setup(user)
+
+ view.Render(w, "page/source", 200, pv)
+
+ return true
+}
+
func pageDelete(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
if (req.Method != "GET" && req.Method != "POST") || strings.LastIndex(req.URL.Path, "/") > len(path) {
return false
@@ -150,12 +171,12 @@ func pageDelete(path string, w http.ResponseWriter, req *http.Request, user *aut
return false
}
- pv := viewmodel.PageView{}
+ pv := viewmodel.PageDelete{}
pv.Page = page
pv.Setup(user)
if user == nil || user.FullID() != page.Author {
- view.Render(w, "message/error-access", http.StatusForbidden, path)
+ view.Render(w, "message", http.StatusForbidden, viewmodel.NewMessage(user, "Access Denied", true, "You are not allowed to delete this page."))
return true
}
@@ -164,7 +185,7 @@ func pageDelete(path string, w http.ResponseWriter, req *http.Request, user *aut
// Catch sneaky shenanigans
if req.Form.Get("aft") != user.Session.ID {
- view.Render(w, "message/error-forgery", http.StatusForbidden, path)
+ view.Render(w, "message", http.StatusForbidden, viewmodel.NewMessage(user, "Forgery Detected", true, "The server thinks something nasty is afoot. Try again if it is your page, and prod me on IRC if it still doesn't work."))
return true
}
@@ -172,12 +193,12 @@ func pageDelete(path string, w http.ResponseWriter, req *http.Request, user *aut
err := page.Delete()
if err != nil {
// It wasn't done D:
- view.Render(w, "message/error-internal", http.StatusInternalServerError, err)
+ view.Render(w, "message", http.StatusInternalServerError, viewmodel.NewMessage(user, "Internal Server Error", true, err.Error()))
return true
}
// It has been done
- view.Render(w, "message/page-deleted", 200, pv)
+ view.Render(w, "message", 200, viewmodel.NewMessage(user, "Deletion Successful", false, "The page has been deleted."))
return true
}
@@ -198,12 +219,10 @@ func pageEdit(path string, w http.ResponseWriter, req *http.Request, user *auth.
return false
}
- pf := viewmodel.PageForm{}
+ pf := viewmodel.PageEdit{}
+ pf.Page = page
pf.Setup(user)
- pf.Operation = "Edit"
- pf.Page = *page
-
if user == nil {
pf.Error = "You are not logged in"
}
@@ -285,5 +304,6 @@ func init() {
PageController.Function("/create", pageCreate)
PageController.Function("/edit/", pageEdit)
PageController.Function("/delete/", pageDelete)
+ PageController.Function("/source/", pageSource)
PageController.Function("/", pageView)
}
diff --git a/controllers/tagcontroller.go b/controllers/tagcontroller.go
deleted file mode 100644
index 3c68132..0000000
--- a/controllers/tagcontroller.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package controllers
-
-import (
- "net/http"
-
- "git.aiterp.net/AiteRP/aitestory/view"
- "git.aiterp.net/AiteRP/aitestory/viewmodel"
-
- "git.aiterp.net/AiteRP/aitestory/model"
- "git.aiterp.net/gisle/wrouter"
- "git.aiterp.net/gisle/wrouter/auth"
-)
-
-// TagController serves and handles the tag managment pages
-var TagController = wrouter.Router{}
-
-func tagList(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
- //var err error
- if (req.Method != "GET" && req.Method != "POST") || len(req.URL.Path) > len(path) {
- return false
- }
-
- tl := viewmodel.TagList{}
- tl.Tags, _ = model.ListTags()
- tl.Setup(user)
-
- view.Render(w, "tags/list", 200, tl)
-
- return true
-}
-
-func init() {
- TagController.Function("/", tagList)
-}
diff --git a/main.go b/main.go
index 597d0f7..dfcaf2a 100644
--- a/main.go
+++ b/main.go
@@ -1,8 +1,14 @@
package main
-import "git.aiterp.net/AiteRP/aitestory/server"
-import "git.aiterp.net/AiteRP/aitestory/controllers"
-import "git.aiterp.net/gisle/wrouter/auth"
+import (
+ "net/http"
+
+ "git.aiterp.net/AiteRP/aitestory/controllers"
+ "git.aiterp.net/AiteRP/aitestory/server"
+ "git.aiterp.net/AiteRP/aitestory/view"
+ "git.aiterp.net/AiteRP/aitestory/viewmodel"
+ "git.aiterp.net/gisle/wrouter/auth"
+)
func main() {
router := &server.Main.Router
@@ -10,10 +16,15 @@ func main() {
auth.Register(&controllers.WikiAthenticator{})
router.Mount("/user", &controllers.UserController)
router.Mount("/page", &controllers.PageController)
- router.Mount("/tags", &controllers.TagController)
router.Mount("/", &controllers.ListController)
router.Static("/ui/", server.Main.Config.Directories.UI)
+ router.Function("/", func(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
+ view.Render(w, "message", http.StatusNotFound, viewmodel.NewMessage(user, "404: "+req.URL.Path, true, "The server don't know what to do with that address."))
+
+ return true
+ })
+
server.Main.Start()
}
diff --git a/model/category.go b/model/category.go
index 5e108a4..639dd3d 100644
--- a/model/category.go
+++ b/model/category.go
@@ -9,6 +9,7 @@ type PageCategory struct {
Key string
Plural string
Icon string
+ Path string
Info string
}
@@ -22,12 +23,12 @@ func (category *PageCategory) URLRoot() string {
// or the database, but for now I think this list is pretty fixed
var PageCategories = []PageCategory{
//{"OoC", "OoC", "O", "OoC content is for announcements, scheduling, general information, or anything that is not in-universe"},
- {"Info", "Info", "i", "Information relevant to RP that might be something looked for in IRC logs"},
- {"News", "News", "N", "News stories that might be pertinent to ongoing plots"},
+ {"Info", "Info", "i", "/info/", "Information relevant to RP that might be something looked for in IRC logs"},
+ {"News", "News", "N", "/news/", "News stories that might be pertinent to ongoing plots"},
//{"Item", "Items", "I", "Items relevant to plots, that is more than just a document saved on a character's own omni-tool"},
- {"Document", "Documents", "D", "Data files, shadow broker dossiers, and other data that is not inside an item"},
- {"Background", "Background", "B", "Rumors, suspicious persons, or inter-RP occurences that may be noticed"},
- {"Story", "Stories", "S", "Background stories and inter-RP character intearactions"},
+ {"Document", "Documents", "D", "/documents/", "Data files, shadow broker dossiers, and other data that is not inside an item"},
+ {"Background", "Background", "B", "/background/", "Rumors, suspicious persons, or inter-RP occurences that may be noticed"},
+ {"Story", "Stories", "S", "/stories/", "Background stories and inter-RP character intearactions"},
}
var pageCategories []string
diff --git a/model/header.go b/model/header.go
index 26c8697..c9bec56 100644
--- a/model/header.go
+++ b/model/header.go
@@ -3,6 +3,7 @@ package model
import (
"database/sql"
"errors"
+ "fmt"
"time"
"git.aiterp.net/AiteRP/aitestory/server"
@@ -34,7 +35,12 @@ func (header *Header) CategoryInfo() PageCategory {
}
}
- return PageCategory{"Unknown", "Unknown", "?", ""}
+ return PageCategory{"Unknown", "Unknown", "?", "/", ""}
+}
+
+// Path returns the path for viewing the page
+func (header *Header) Path() string {
+ return fmt.Sprintf("/page/%s", header.ID)
}
// ListHeaders grabs all the general pages from
@@ -104,6 +110,72 @@ func ListHeadersByCategory(category string) ([]Header, error) {
return results, nil
}
+// ListHeadersByAuthor grabs all the pages by the given author
+func ListHeadersByAuthor(author string) ([]Header, error) {
+ const query = `
+ SELECT page.id,page.name,author,category,fictional_date,publish_date,edit_date,tag.id,tag.type,tag.name
+ FROM page
+ LEFT JOIN page_tag ON (page.id = page_tag.page_id AND page_tag.primary = true)
+ LEFT JOIN tag ON (tag.id = page_tag.tag_id)
+ WHERE page.specific=false AND page.published=true AND page.unlisted=false AND page.author = ?
+ ORDER BY page.publish_date DESC
+ `
+
+ db := server.Main.DB
+
+ rows, err := db.Query(query, author)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ results := make([]Header, 0, 64)
+ header := Header{}
+ for rows.Next() {
+ err := parseHeader(&header, rows)
+ if err != nil {
+ return nil, err
+ }
+
+ results = append(results, header)
+ }
+
+ return results, nil
+}
+
+// ListHeadersByMonth grabs all the pages within the given month
+func ListHeadersByMonth(year int, month int) ([]Header, error) {
+ const query = `
+ SELECT page.id,page.name,author,category,fictional_date,publish_date,edit_date,tag.id,tag.type,tag.name
+ FROM page
+ LEFT JOIN page_tag ON (page.id = page_tag.page_id AND page_tag.primary = true)
+ LEFT JOIN tag ON (tag.id = page_tag.tag_id)
+ WHERE page.specific=false AND page.published=true AND page.unlisted=false AND YEAR(fictional_date) = ? AND MONTH(fictional_date) = ?
+ ORDER BY page.publish_date DESC
+ `
+
+ db := server.Main.DB
+
+ rows, err := db.Query(query, year, month)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ results := make([]Header, 0, 64)
+ header := Header{}
+ for rows.Next() {
+ err := parseHeader(&header, rows)
+ if err != nil {
+ return nil, err
+ }
+
+ results = append(results, header)
+ }
+
+ return results, nil
+}
+
// ListHeadersByTag lists all headers that has the tag. Leave the category empty
// to not filter by it
func ListHeadersByTag(category string, tag *Tag) ([]Header, error) {
diff --git a/model/page.go b/model/page.go
index a170b68..099c850 100644
--- a/model/page.go
+++ b/model/page.go
@@ -139,7 +139,7 @@ func (page *Page) Update() error {
}
// Stop now if the tages haven't changed
- if len(page.prevTags) == len(page.Tags) {
+ if len(page.Tags) > 0 && len(page.prevTags) == len(page.Tags) {
change := false
for i, tag := range page.prevTags {
@@ -265,6 +265,11 @@ func (page *Page) ParseForm(form url.Values) []error {
return errors
}
+// OpPath gets a path associated with a specific operation on this page.
+func (page *Page) OpPath(op string) string {
+ return fmt.Sprintf("/page/%s/%s", op, page.ID)
+}
+
// Standardize page ID generation
func (page *Page) generateID() {
page.ID = generate.FriendlyID(16)
diff --git a/model/tag.go b/model/tag.go
index 0d78245..18dabaf 100644
--- a/model/tag.go
+++ b/model/tag.go
@@ -18,6 +18,15 @@ var TagTypes = []string{
"Series",
}
+// TagTitles are the titles to use when listing tags
+var TagTitles = map[string]string{
+ "Location": "Locations",
+ "Character": "Characters",
+ "Event": "Plots & Events",
+ "Organization": "Organizations",
+ "Series": "Series",
+}
+
// Tag describes a tag
type Tag struct {
ID string
@@ -121,10 +130,14 @@ func (tag *Tag) Validate() error {
return nil
}
-// Hook returns the url friendly name, which is pretty much just
-// adding underscores to it.
-func (tag Tag) Hook() string {
- return strings.Replace(tag.Name, " ", "_", -1)
+// Path returns a path used for the tag's list page
+func (tag Tag) Path() string {
+ return fmt.Sprintf("/%s/%s", strings.ToLower(tag.Type), strings.Replace(tag.Name, " ", "_", -1))
+}
+
+// CSSClass gets the tag's css class, which determines its color.
+func (tag Tag) CSSClass() string {
+ return fmt.Sprintf("ttype-%s", strings.ToLower(tag.Type))
}
// FindTag finds a tag by ID. Leave tagtype blank to ignore it. Both key and
diff --git a/view/amber/base/master.amber b/view/amber/base/master.amber
new file mode 100644
index 0000000..1edd5aa
--- /dev/null
+++ b/view/amber/base/master.amber
@@ -0,0 +1,44 @@
+doctype 5
+
+import mixins
+
+html
+ head
+ block meta
+ meta[name="description"][content="This is a great website"]
+ meta[charset="UTF-8"]
+ meta[name="viewport"][content="width=device-width, initial-scale=1.0, maximum-scale=2.0, user-scalable=no"]
+ meta[name="theme-color"][content="#112233"]
+ meta[http-equiv="Content-Type"][content="text/html; charset=utf-8"]
+
+ block css
+ link[rel="stylesheet"][href="/ui/css/base.css"]
+ link[rel="stylesheet"][href="/ui/css/magic.css"]
+ link[rel="stylesheet"][href="/ui/css/theme.css"]
+ link[rel="stylesheet"][media="screen"][href="/ui/fonts/source-sans-pro/source-sans-pro.css"][type="text/css"]
+
+ block js
+ script[type="text/javascript"][src="/ui/js/background.js"]
+
+ title #{ViewTitle}
+ body
+ if ViewBackground != ""
+ img[id="main-background"][src="/ui/img/bg.png"]
+ else
+ img[id="main-background"][src="/ui/img/bg.png"]
+
+ div.content-wrapper
+ nav
+ block menu
+ if User.LoggedIn
+ ul
+ +menuitem("/user/logout", "U", "Logout")
+ else
+ ul
+ +menuitem("/user/login", "U", "Login")
+
+ if ViewPath != "/"
+ +menuitem("/", "<", "Back")
+
+ main
+ block main
\ No newline at end of file
diff --git a/view/amber/base/mixins.amber b/view/amber/base/mixins.amber
new file mode 100644
index 0000000..b19512b
--- /dev/null
+++ b/view/amber/base/mixins.amber
@@ -0,0 +1,30 @@
+$root = $
+
+mixin menuitem($path, $icon, $text)
+ li
+ .selected ? $root.ViewPath == $path
+ a[href=$path]
+ div.mg-icon #{$icon}
+ div.mg-label #{$text}
+
+mixin tagmenuitem($tag)
+ li
+ [class=$tag.CSSClass]
+ a[href=$tag.Path]
+ div.mg-icon #{$tag.Icon}
+ div.mg-label #{$tag.Name}
+
+
+
+mixin formoption($name, $selected, $label, $info)
+ div.radio-wrapper
+ $id = printf("checkbox-%s", $name)
+
+ if $selected
+ input[id=$id][type="checkbox"][name=$name][value="true"][checked]
+ else
+ input[id=$id][type="checkbox"][name=$name][value="true"]
+
+ label[for="checkbox-unlisted"]
+ b #{$label}:
+ spamn #{$info}
\ No newline at end of file
diff --git a/view/amber/create.amber b/view/amber/create.amber
new file mode 100644
index 0000000..66e38cb
--- /dev/null
+++ b/view/amber/create.amber
@@ -0,0 +1,63 @@
+extends base/master
+
+block append css
+ link[rel="stylesheet"][href="/ui/css/form.css"]
+
+block append js
+ script[type="text/javascript"][src="/ui/js/form-page.js"]
+
+block menu
+ import menu
+
+block main
+ $page = $.Page
+
+ article
+ h1 Create
+ form[action="/page/create"][method="POST"]
+ p.danger #{$.Error}
+
+ input.big
+ [placeholder="Page Name"]
+ [value=$page.Name]
+ [type="text"]
+ [name="name"]
+ textarea.tall
+ [placeholder="Content"]
+ [name="source"]
+ | #{$page.Source}
+ input
+ [placeholder="IC Date (e.g. 'Oct 27, 2185')"]
+ [name="fictionalDate"]
+ [type="text"]
+ [value=$page.FictionalDate] ? !$page.FictionalDate.IsZero
+
+ h2 Category
+ div.group[title="Category"]
+ each $category in $.Categories
+ div.radio-wrapper
+ $radioid = printf("radio-%s", $category.Key)
+ if $category.Key == $page.Category
+ input[id=$radioid][name="category"][type="radio"][name="category"][value=$category.Key][checked]
+ else
+ input[id=$radioid][name="category"][type="radio"][name="category"][value=$category.Key]
+ label[for=$radioid]
+ b #{$category.Key}:
+ span #{$category.Info}
+
+ h2 Tags
+ textarea
+ [name="tags"]
+ [placeholder="Location: Miner's Respite\nOrganization: Redrock Agency\nCharacter: Renala T'Iavay\nEvent: Skipping Work\nSeries: Just Another Tuesday"]
+ | #{$.TagInput}
+
+ h2 Options
+ div.group
+ +formoption("unlisted", $page.Unlisted, "Unlisted", "The page will not show up in any page list. Meant for omni-tool messages, quick copypastes and so on.")
+ +formoption("indexed", $page.Unlisted, "Indexable", "Third-party search engines (that play by the rules) are permitted to crawl this page.")
+
+ // Future options (maybe)
+ input[type="hidden"][name="type"][value="Markdown"]
+ input[type="hidden"][name="published"][value="True"]
+
+ button[type="submit"] Create
diff --git a/view/amber/index.amber b/view/amber/index.amber
new file mode 100644
index 0000000..1db3afc
--- /dev/null
+++ b/view/amber/index.amber
@@ -0,0 +1,25 @@
+extends base/master
+
+block menu
+ import menu
+
+block main
+ article
+ table.page-list
+ tbody
+ each $header in Headers
+ tr
+ td.pl-icon #{$header.CategoryInfo.Icon}
+ td.pl-content
+ div.plc-title
+ a[href=$header.Path] #{$header.Name}
+ div.plc-meta
+ div.plcm-date #{formatDate($header.PublishDate)}
+ if $header.Dated
+ div.plcm-date #{formatDate($header.FictionalDate)}
+ if $header.PrimaryTag
+ div.plcm-tag[class=$header.PrimaryTag.CSSCLass] #{$header.PrimaryTag.Name}
+ div.plcm-author #{formatUserID($header.Author)}
+ tr.spacer
+ td
+
diff --git a/view/amber/menu.amber b/view/amber/menu.amber
new file mode 100644
index 0000000..85b25db
--- /dev/null
+++ b/view/amber/menu.amber
@@ -0,0 +1,25 @@
+import base/mixins
+
+$authorPath = printf("/author/%s", ActiveAuthor)
+
+a[href="/"]
+ h1 Aite RP
+
+ul
+ if User.LoggedIn
+ +menuitem("/page/create", "+", "Create")
+
+ul
+ each $category in Categories
+ +menuitem($category.Path, $category.Icon, $category.Plural)
+
+ul
+ if ActiveTag.ID
+ +menuitem(ActiveTag.Path, ActiveTag.Icon, ActiveTag.Name)
+ if ActiveDate
+ +menuitem(ActiveDatePath, "D", ActiveDate)
+ if ActiveAuthor
+ +menuitem($authorPath, "A", formatUserID(ActiveAuthor))
+
+ul
+ +menuitem("/tags/", "T", "Tags")
\ No newline at end of file
diff --git a/view/amber/message.amber b/view/amber/message.amber
new file mode 100644
index 0000000..12e7307
--- /dev/null
+++ b/view/amber/message.amber
@@ -0,0 +1,12 @@
+extends base/master
+
+block menu
+ a[href="/"]
+ h1 Aite RP
+
+block main
+ article
+ h1
+ .danger ? $.Danger
+ | #{$.Title}
+ p #{$.Text}
\ No newline at end of file
diff --git a/view/amber/page/delete.amber b/view/amber/page/delete.amber
new file mode 100644
index 0000000..bfdb052
--- /dev/null
+++ b/view/amber/page/delete.amber
@@ -0,0 +1,30 @@
+extends ../base/master
+
+block append css
+ link[rel="stylesheet"][href="/ui/css/form.css"]
+
+block append js
+ script[type="text/javascript"][src="/ui/js/form-page.js"]
+
+block menu
+ import menu
+
+block main
+ $page = $.Page
+
+ article
+ h1.danger Delete
+ form[action=$page.OpPath("delete")][method="POST"]
+ p.danger This is irreversible, so make sure you are deleting the right page.
+
+ ul
+ li ID: #{$.Page.ID}
+ li Name: #{$.Page.Name}
+ li Category: #{$.Page.Category}
+ li Published: #{formatDateLong($.Page.PublishDate)}
+ ul
+
+ input[type="hidden"][name="aft"][value=$.User.SessionID]
+
+
+ button[type="submit"] Delete
diff --git a/view/amber/page/edit.amber b/view/amber/page/edit.amber
new file mode 100644
index 0000000..ca5837b
--- /dev/null
+++ b/view/amber/page/edit.amber
@@ -0,0 +1,64 @@
+extends ../base/master
+
+
+block append css
+ link[rel="stylesheet"][href="/ui/css/form.css"]
+
+block append js
+ script[type="text/javascript"][src="/ui/js/form-page.js"]
+
+block menu
+ import menu
+
+block main
+ $page = $.Page
+
+ article
+ h1 Create
+ form[action=$page.OpPath("edit")][method="POST"]
+ p.danger #{$.Error}
+
+ input.big
+ [placeholder="Page Name"]
+ [value=$page.Name]
+ [type="text"]
+ [name="name"]
+ textarea.tall
+ [placeholder="Content"]
+ [name="source"]
+ | #{$page.Source}
+ input
+ [placeholder="IC Date (e.g. 'Oct 27, 2185')"]
+ [name="fictionalDate"]
+ [type="text"]
+ [value=$page.FictionalDate] ? !$page.FictionalDate.IsZero
+
+ h2 Category
+ div.group[title="Category"]
+ each $category in $.Categories
+ div.radio-wrapper
+ $radioid = printf("radio-%s", $category.Key)
+ if $category.Key == $page.Category
+ input[id=$radioid][name="category"][type="radio"][name="category"][value=$category.Key][checked]
+ else
+ input[id=$radioid][name="category"][type="radio"][name="category"][value=$category.Key]
+ label[for=$radioid]
+ b #{$category.Key}:
+ span #{$category.Info}
+
+ h2 Tags
+ textarea
+ [name="tags"]
+ [placeholder="Location: Miner's Respite\nOrganization: Redrock Agency\nCharacter: Renala T'Iavay\nEvent: Skipping Work\nSeries: Just Another Tuesday"]
+ | #{$.TagInput}
+
+ h2 Options
+ div.group
+ +formoption("unlisted", $page.Unlisted, "Unlisted", "The page will not show up in any page list. Meant for omni-tool messages, quick copypastes and so on.")
+ +formoption("indexed", $page.Indexed, "Indexable", "Third-party search engines (that play by the rules) are permitted to crawl this page.")
+
+ // Future options (maybe)
+ input[type="hidden"][name="type"][value="Markdown"]
+ input[type="hidden"][name="published"][value="True"]
+
+ button[type="submit"] Edit
diff --git a/view/amber/page/menu.amber b/view/amber/page/menu.amber
new file mode 100644
index 0000000..2efde11
--- /dev/null
+++ b/view/amber/page/menu.amber
@@ -0,0 +1,29 @@
+import ../base/mixins
+
+$pagePath = printf("/page/%s", $.Page.ID)
+$pageEditPath = printf("/page/edit/%s", $.Page.ID)
+$pageDeletePath = printf("/page/delete/%s", $.Page.ID)
+$pageSourcePath = printf("/page/source/%s", $.Page.ID)
+$datePath = printf("/month/%s", $.Page.FictionalDate.UTC.Format("2006-01"))
+$authorPath = printf("/author/%s", $.Page.Author)
+
+a[href="/"]
+ h1 Page
+
+if !$.HideMenu
+ ul
+ +menuitem($pagePath, "V", "View")
+ if $.Page.Author == $.User.ID
+ +menuitem($pageEditPath, "E", "Edit")
+ +menuitem($pageDeletePath, "X", "Delete")
+ else
+ +menuitem($pageSourcePath, "#", "Source")
+
+ ul
+ each $tag in $.Page.Tags
+ +tagmenuitem($tag)
+
+ ul
+ if $.Page.Dated
+ +menuitem($datePath, "D", formatDate($.Page.FictionalDate))
+ +menuitem($authorPath, "A", formatUserID($.Page.Author))
diff --git a/view/amber/page/source.amber b/view/amber/page/source.amber
new file mode 100644
index 0000000..058d78f
--- /dev/null
+++ b/view/amber/page/source.amber
@@ -0,0 +1,14 @@
+extends ../base/master
+
+block append meta
+ if !$.Page.Indexed
+ meta[name="robots"][content="noindex"]
+ meta[name="googlebot"][content="noindex"]
+
+block menu
+ import menu
+
+block main
+ article
+ code.block
+ #{$.Page.Source}
\ No newline at end of file
diff --git a/view/amber/page/view.amber b/view/amber/page/view.amber
new file mode 100644
index 0000000..e45dee9
--- /dev/null
+++ b/view/amber/page/view.amber
@@ -0,0 +1,13 @@
+extends ../base/master
+
+block append meta
+ if !$.Page.Indexed
+ meta[name="robots"][content="noindex"]
+ meta[name="googlebot"][content="noindex"]
+
+block menu
+ import menu
+
+block main
+ article.narrow
+ #{$.Page.Content}
\ No newline at end of file
diff --git a/view/amber/tags.amber b/view/amber/tags.amber
new file mode 100644
index 0000000..aa13821
--- /dev/null
+++ b/view/amber/tags.amber
@@ -0,0 +1,17 @@
+extends base/master
+
+block menu
+ import menu
+
+block main
+ article
+ h1 All Tags
+ div.tag-list
+ each $key, $tags in $.Map
+ if $tags
+ div.tl-item
+ h2 #{$key}
+ ul
+ each $tag in $tags
+ li
+ a[class=$tag.CSSClass][href=$tag.Path] #{$tag.Name}
\ No newline at end of file
diff --git a/view/amber/user/login.amber b/view/amber/user/login.amber
new file mode 100644
index 0000000..1f9dd1b
--- /dev/null
+++ b/view/amber/user/login.amber
@@ -0,0 +1,26 @@
+extends ../base/master
+
+block append css
+ link[rel="stylesheet"][href="/ui/css/form.css"]
+
+block menu
+ import menu
+
+block main
+ article
+ h1 Login
+ form[action="/user/login"][method="POST"]
+ p Use your wiki.aiterp.net account.
+ p.danger #{$.Error}
+ input
+ [placeholder="Username"]
+ [name="username"]
+ [type="text"]
+ [value=$.UserName]
+ [autofocus] ? $.UserName == ""
+ input
+ [placeholder="Password"]
+ [name="password"]
+ [type="password"]
+ [autofocus] ? $.UserName != ""
+ button[type="submit"] Login
\ No newline at end of file
diff --git a/view/amber/user/menu.amber b/view/amber/user/menu.amber
new file mode 100644
index 0000000..c596f06
--- /dev/null
+++ b/view/amber/user/menu.amber
@@ -0,0 +1,4 @@
+import ../base/mixins
+
+a[href="/"]
+ h1 User
\ No newline at end of file
diff --git a/view/renderer.go b/view/renderer.go
index a0f14cd..bf56b9a 100644
--- a/view/renderer.go
+++ b/view/renderer.go
@@ -2,12 +2,14 @@ package view
import (
"errors"
+ "fmt"
"html/template"
"io"
"log"
"net/http"
"os"
- "path"
+
+ "github.com/eknkc/amber"
"git.aiterp.net/AiteRP/aitestory/server"
"git.aiterp.net/gisle/wrouter/response"
@@ -17,52 +19,33 @@ var wd, _ = os.Getwd()
var cache = make(map[string]*template.Template)
var argsCache = make(map[string][]string)
-// Register registers a template and compiles it for rendering. This should be done
-// in the beginning since an error will terminate the server
-func Register(name string, base string, fragments ...string) {
- rootPath := server.Main.Config.Directories.Templates
-
- for i, fragment := range fragments {
- fragments[i] = path.Join(rootPath, fragment+".tmpl")
- }
-
- args := append([]string{path.Join(rootPath, name+".tmpl"), path.Join(rootPath, base+".tmpl")}, fragments...)
- tmpl, err := template.New(name).Funcs(funcMap).ParseFiles(args...)
- if err != nil {
- log.Fatalf("Failed to register %s: %s", name, err)
- }
-
- argsCache[name] = args
- cache[name] = tmpl
-}
+var defaultOptions = amber.Options{PrettyPrint: true}
+var defaultDirOptions = amber.DirOptions{Ext: ".amber", Recursive: true}
// Render renders a template with the name it was registered with, and with the
// view model. The view model is expected to be the correct model from the viewmodel
// package
func Render(w http.ResponseWriter, name string, status int, viewModel interface{}) {
- var tmpl *template.Template
var err error
if server.Main.Config.Server.Debug {
- tmpl, err = template.New(name).Funcs(funcMap).ParseFiles(argsCache[name]...)
+ cache, err = amber.CompileDir(server.Main.Config.Directories.Templates, defaultDirOptions, defaultOptions)
if err != nil {
- response.Text(w, 500, "Failed to run template "+name+": "+err.Error())
- return
+ log.Println(err)
}
- } else {
- var ok bool
+ }
- tmpl, ok = cache[name]
- if !ok {
- response.Text(w, 500, "Template not found: "+name)
- return
- }
+ tmpl, ok := cache[name]
+ if !ok {
+ response.Text(w, 500, "Template not found: "+name)
+ return
}
w.WriteHeader(status)
- err = tmpl.ExecuteTemplate(w, "base", viewModel)
+ err = tmpl.Execute(w, viewModel)
if err != nil {
log.Println("Template error:", err.Error())
+ response.Text(w, 500, "Template error: "+err.Error())
}
}
@@ -77,11 +60,31 @@ func Run(w io.Writer, name string, viewModel interface{}) error {
}
func init() {
- Register("index", "base/default")
- Register("user/login", "base/default")
- Register("page/create", "base/default")
- Register("page/edit", "base/default")
- Register("page/view", "base/default")
- Register("page/delete", "base/default")
- Register("tags/list", "base/default")
+ var err error
+
+ for key, value := range funcMap {
+ if _, exists := amber.FuncMap[key]; exists {
+ log.Printf("Amber already provides a function by the name: %s", key)
+ }
+
+ amber.FuncMap[key] = value
+ }
+
+ cache, err = amber.CompileDir(server.Main.Config.Directories.Templates, defaultDirOptions, defaultOptions)
+ if err != nil {
+ if server.Main.Config.Server.Debug {
+ log.Println(err)
+ return
+ }
+
+ log.Fatalln(err)
+ }
+
+ if server.Main.Config.Server.Debug {
+ fmt.Printf("Template directory: %s\n", server.Main.Config.Directories.Templates)
+
+ for key := range cache {
+ fmt.Printf("Template loaded: %s\n", key)
+ }
+ }
}
diff --git a/view/templates/base/default.tmpl b/view/templates/base/default.tmpl
deleted file mode 100644
index 10027cb..0000000
--- a/view/templates/base/default.tmpl
+++ /dev/null
@@ -1,41 +0,0 @@
-{{define "base"}}
-
-
-
-
-
- {{ .ViewTitle }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ block "head" . }}{{end}}
-
-
-
-
-
-
-
- {{ block "content" . }}{{end}}
-
-
-
-
-
-
-{{end}}
\ No newline at end of file
diff --git a/view/templates/index.tmpl b/view/templates/index.tmpl
deleted file mode 100644
index bc544b4..0000000
--- a/view/templates/index.tmpl
+++ /dev/null
@@ -1,66 +0,0 @@
-{{ define "content" }}
-
-
- {{ range .Headers }}
-
-
- {{.CategoryInfo.Icon}} |
-
-
-
- |
-
- |
- {{ end }}
-
-
-{{ end }}
-
-{{ define "menu" }}
- Aite RP
-
-
-
- {{ if $.ActiveTag.ID }}
-
- {{ end }}
-
-
-
- {{ if $.User.LoggedIn }}
-
-
-
- {{ else }}
-
- {{ end }}
-
-
-{{ end }}
-
-{{ define "head" }}
-
-{{ end }}
\ No newline at end of file
diff --git a/view/templates/page/create.tmpl b/view/templates/page/create.tmpl
deleted file mode 100644
index 02dc8da..0000000
--- a/view/templates/page/create.tmpl
+++ /dev/null
@@ -1,44 +0,0 @@
-{{ define "content" }}
-
- {{$.Operation}}
-
-
-{{ end }}
-
-{{ define "menu" }}
- Aite RP
-
-
-{{ end }}
-
-{{ define "head" }}
-
-
-{{ end }}
\ No newline at end of file
diff --git a/view/templates/page/delete.tmpl b/view/templates/page/delete.tmpl
deleted file mode 100644
index e28e8d2..0000000
--- a/view/templates/page/delete.tmpl
+++ /dev/null
@@ -1,37 +0,0 @@
-{{ define "content" }}
-
- Delete Page
-
-{{ end }}
-
-{{ define "menu" }}
- Page
-
- {{ if eq $.User.ID $.Page.Author}}
-
- {{ end }}
-
-
-{{ end }}
-
-{{ define "head" }}
-
-{{ end }}
\ No newline at end of file
diff --git a/view/templates/page/edit.tmpl b/view/templates/page/edit.tmpl
deleted file mode 100644
index 3c9bebe..0000000
--- a/view/templates/page/edit.tmpl
+++ /dev/null
@@ -1,44 +0,0 @@
-{{ define "content" }}
-
- {{$.Operation}}
-
-
-{{ end }}
-
-{{ define "menu" }}
- Aite RP
-
-
-{{ end }}
-
-{{ define "head" }}
-
-
-{{ end }}
\ No newline at end of file
diff --git a/view/templates/page/view.tmpl b/view/templates/page/view.tmpl
deleted file mode 100644
index e43b0b6..0000000
--- a/view/templates/page/view.tmpl
+++ /dev/null
@@ -1,44 +0,0 @@
-{{ define "content" }}
-
- {{$.Page.Content}}
-
-{{ end }}
-
-{{ define "menu" }}
- Page
- {{ if $.Page.Dated}}
- {{$.Page.FictionalDate | formatDate}}
- {{ else }}
- {{$.Page.PublishDate | formatDate}}
- {{ end }}
-
-
-
- {{ if eq $.User.ID $.Page.Author}}
-
- {{ end }}
-
-
-
- {{ if $.User.LoggedIn }}
-
- {{ else }}
-
- {{ end }}
-{{ end }}
-
-{{ define "head" }}
-{{ end }}
\ No newline at end of file
diff --git a/view/templates/tags/list.tmpl b/view/templates/tags/list.tmpl
deleted file mode 100644
index 4a2ba07..0000000
--- a/view/templates/tags/list.tmpl
+++ /dev/null
@@ -1,48 +0,0 @@
-{{ define "content" }}
-
- All Tags
-
-
- {{ range $tagHeader, $tags := .Map }}
-
- {{ end }}
-
-
-
-
-{{ end }}
-
-{{ define "menu" }}
- Tags
-
-
-
- {{ if $.User.LoggedIn }}
-
-
-
- {{ else }}
-
- {{ end }}
-
-
-{{ end }}
-
-{{ define "head" }}
-
-{{ end }}
\ No newline at end of file
diff --git a/view/templates/user/login.tmpl b/view/templates/user/login.tmpl
deleted file mode 100644
index 37b7aaa..0000000
--- a/view/templates/user/login.tmpl
+++ /dev/null
@@ -1,24 +0,0 @@
-{{ define "content" }}
-
- Login
-
-
-{{ end }}
-
-{{ define "menu" }}
- Aite RP
-
-
-{{ end }}
-
-{{ define "head" }}
-
-{{ end }}
\ No newline at end of file
diff --git a/viewmodel/base.go b/viewmodel/base.go
index 3e9ff94..ae10e45 100644
--- a/viewmodel/base.go
+++ b/viewmodel/base.go
@@ -16,11 +16,14 @@ type Base struct {
LoggedIn bool
SessionID string
}
- ViewTitle string
+ ViewBackground string
+ ViewPath string
+ ViewTitle string
+ Message string
}
// InitBase initializes the base of the viewmodel
-func (base *Base) setupBase(user *auth.User, viewTitle string) {
+func (base *Base) setupBase(user *auth.User, viewTitle string, viewPath string) {
if user != nil {
base.User.ID = user.FullID()
base.User.Name = user.ID
@@ -29,5 +32,7 @@ func (base *Base) setupBase(user *auth.User, viewTitle string) {
base.User.SessionID = user.Session.ID
}
+ base.ViewPath = viewPath
+
base.ViewTitle = fmt.Sprintf("%s - %s", viewTitle, server.Main.Config.View.Title)
}
diff --git a/viewmodel/indexbase.go b/viewmodel/indexbase.go
new file mode 100644
index 0000000..21aa92b
--- /dev/null
+++ b/viewmodel/indexbase.go
@@ -0,0 +1,16 @@
+package viewmodel
+
+import "git.aiterp.net/AiteRP/aitestory/model"
+
+// IndexBase is used for the index menu.
+type IndexBase struct {
+ Categories []model.PageCategory
+ ActiveTag model.Tag
+ ActiveAuthor string
+ ActiveDate string
+ ActiveDatePath string
+}
+
+func (im *IndexBase) setupMenu() {
+ im.Categories = model.PageCategories
+}
diff --git a/viewmodel/pagelist.go b/viewmodel/indexlist.go
similarity index 58%
rename from viewmodel/pagelist.go
rename to viewmodel/indexlist.go
index a622d2b..d18a1eb 100644
--- a/viewmodel/pagelist.go
+++ b/viewmodel/indexlist.go
@@ -5,18 +5,18 @@ import (
"git.aiterp.net/gisle/wrouter/auth"
)
-// PageList is a view model for rendering the front page
-type PageList struct {
+// IndexList is a view model for rendering the front page
+type IndexList struct {
Base
+ IndexBase
Headers []model.Header
ActiveCategory model.PageCategory
- Categories []model.PageCategory
- ActiveTag model.Tag
FavoriteTags []model.Tag
}
// Setup sets up the page model and the base, and should
// be run after the details have been filled in.
-func (pl *PageList) Setup(user *auth.User) {
- pl.setupBase(user, "Index")
+func (il *IndexList) Setup(user *auth.User, viewPath string, viewTitle string) {
+ il.setupMenu()
+ il.setupBase(user, viewTitle, viewPath)
}
diff --git a/viewmodel/indextags.go b/viewmodel/indextags.go
new file mode 100644
index 0000000..e65851d
--- /dev/null
+++ b/viewmodel/indextags.go
@@ -0,0 +1,49 @@
+package viewmodel
+
+import (
+ "fmt"
+
+ "git.aiterp.net/AiteRP/aitestory/model"
+ "git.aiterp.net/gisle/wrouter/auth"
+)
+
+// IndexTags is a view model for rendering the tag lists.
+type IndexTags struct {
+ Base
+ IndexBase
+
+ Type string
+ Tags []model.Tag
+ TagCategories []string
+
+ tagMap map[string][]model.Tag
+}
+
+// Map lazy-loads the map of tags, which is only
+// used when listing all of them.
+func (it IndexTags) Map() map[string][]model.Tag {
+ // Set up the map
+ it.tagMap = make(map[string][]model.Tag, len(model.TagTypes))
+ for _, tagType := range model.TagTypes {
+ it.tagMap[tagType] = make([]model.Tag, 0, 64)
+ }
+
+ // Organize
+ for _, tag := range it.Tags {
+ it.tagMap[tag.Type] = append(it.tagMap[tag.Type], tag)
+ }
+
+ return it.tagMap
+}
+
+// Setup sets up the page model and the base, and should
+// be run after the details have been filled in.
+func (it *IndexTags) Setup(user *auth.User, viewPath string) {
+ title := it.Type
+ if it.Type != "" {
+ title = "All"
+ }
+
+ it.setupMenu()
+ it.setupBase(user, fmt.Sprintf("%s Tags", title), viewPath)
+}
diff --git a/viewmodel/message.go b/viewmodel/message.go
new file mode 100644
index 0000000..368ff2e
--- /dev/null
+++ b/viewmodel/message.go
@@ -0,0 +1,19 @@
+package viewmodel
+
+import "git.aiterp.net/gisle/wrouter/auth"
+
+// Message is a simple viewmodel for the message pages
+type Message struct {
+ Base
+ Title string
+ Text string
+ Danger bool
+}
+
+// NewMessage creates a message model
+func NewMessage(user *auth.User, title string, danger bool, text string) *Message {
+ msg := &Message{Title: title, Text: text, Danger: danger}
+ msg.setupBase(user, title, "")
+
+ return msg
+}
diff --git a/viewmodel/pagebase.go b/viewmodel/pagebase.go
new file mode 100644
index 0000000..3c5d37c
--- /dev/null
+++ b/viewmodel/pagebase.go
@@ -0,0 +1,9 @@
+package viewmodel
+
+import "git.aiterp.net/AiteRP/aitestory/model"
+
+// PageBase describes the basic parts of a page.
+type PageBase struct {
+ Page *model.Page
+ HideMenu bool
+}
diff --git a/viewmodel/pagecreate.go b/viewmodel/pagecreate.go
new file mode 100644
index 0000000..e435bcf
--- /dev/null
+++ b/viewmodel/pagecreate.go
@@ -0,0 +1,26 @@
+package viewmodel
+
+import (
+ "git.aiterp.net/AiteRP/aitestory/model"
+ "git.aiterp.net/gisle/wrouter/auth"
+)
+
+// PageCreate is the view model for the page create form.
+type PageCreate struct {
+ Base
+ IndexBase
+
+ Page model.Page
+ Error string
+ TagInput string
+}
+
+// Setup sets the view model up.
+func (pf *PageCreate) Setup(user *auth.User) {
+ pf.setupMenu()
+ pf.setupBase(user, "Create", "/page/create")
+
+ pf.Categories = model.PageCategories
+
+ pf.Page.Defaults()
+}
diff --git a/viewmodel/pagedelete.go b/viewmodel/pagedelete.go
new file mode 100644
index 0000000..625687d
--- /dev/null
+++ b/viewmodel/pagedelete.go
@@ -0,0 +1,19 @@
+package viewmodel
+
+import (
+ "fmt"
+
+ "git.aiterp.net/gisle/wrouter/auth"
+)
+
+// PageDelete is the view model used to view the page's delete form.
+type PageDelete struct {
+ Base
+ PageBase
+}
+
+// Setup sets up the page view model. It should be calles last
+func (pv *PageDelete) Setup(user *auth.User) {
+ pv.HideMenu = false
+ pv.setupBase(user, pv.Page.Name, fmt.Sprintf("/page/delete/%s", pv.Page.ID))
+}
diff --git a/viewmodel/pageform.go b/viewmodel/pageedit.go
similarity index 50%
rename from viewmodel/pageform.go
rename to viewmodel/pageedit.go
index c84ac79..7022a00 100644
--- a/viewmodel/pageform.go
+++ b/viewmodel/pageedit.go
@@ -5,17 +5,19 @@ import (
"git.aiterp.net/gisle/wrouter/auth"
)
-type PageForm struct {
+// PageEdit is the view model for the page edit form.
+type PageEdit struct {
Base
- Page model.Page
+ PageBase
+
Categories []model.PageCategory
- Operation string
Error string
TagInput string
}
-func (pf *PageForm) Setup(user *auth.User) {
- pf.setupBase(user, "Create")
+// Setup sets the view model up.
+func (pf *PageEdit) Setup(user *auth.User) {
+ pf.setupBase(user, "Edit", "/page/edit/"+pf.Page.ID)
+
pf.Categories = model.PageCategories
- pf.Page.Defaults()
}
diff --git a/viewmodel/pagesource.go b/viewmodel/pagesource.go
new file mode 100644
index 0000000..9ba7a8d
--- /dev/null
+++ b/viewmodel/pagesource.go
@@ -0,0 +1,20 @@
+package viewmodel
+
+import (
+ "fmt"
+
+ "git.aiterp.net/gisle/wrouter/auth"
+)
+
+// PageSource is the view model used to view the page's source.
+// It's got no extra data on its own.
+type PageSource struct {
+ Base
+ PageBase
+}
+
+// Setup sets up the page view model. It should be calles last
+func (pv *PageSource) Setup(user *auth.User) {
+ pv.HideMenu = false
+ pv.setupBase(user, pv.Page.Name, fmt.Sprintf("/page/source/%s", pv.Page.ID))
+}
diff --git a/viewmodel/pageview.go b/viewmodel/pageview.go
index e3f28e1..0fc4ea3 100644
--- a/viewmodel/pageview.go
+++ b/viewmodel/pageview.go
@@ -1,15 +1,20 @@
package viewmodel
import (
- "git.aiterp.net/AiteRP/aitestory/model"
+ "fmt"
+
"git.aiterp.net/gisle/wrouter/auth"
)
+// PageView is the view model used to view the page. It's got no extra
+// data on its own.
type PageView struct {
Base
- Page *model.Page
+ PageBase
}
+// Setup sets up the page view model. It should be calles last
func (pv *PageView) Setup(user *auth.User) {
- pv.setupBase(user, pv.Page.Name)
+ pv.HideMenu = false
+ pv.setupBase(user, pv.Page.Name, fmt.Sprintf("/page/%s", pv.Page.ID))
}
diff --git a/viewmodel/taglist.go b/viewmodel/taglist.go
deleted file mode 100644
index c02a515..0000000
--- a/viewmodel/taglist.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package viewmodel
-
-import (
- "fmt"
-
- "git.aiterp.net/AiteRP/aitestory/model"
- "git.aiterp.net/gisle/wrouter/auth"
-)
-
-// TagList is a view model for rendering the tag lists.
-type TagList struct {
- Base
- Type string
- Tags []model.Tag
- TagCategories []string
-
- tagMap map[string][]model.Tag
-}
-
-// Map lazy-loads the map of tags, which is only
-// used when listing all of them.
-func (tl TagList) Map() map[string][]model.Tag {
- // Set up the map
- tl.tagMap = make(map[string][]model.Tag, len(model.TagTypes))
- for _, tagType := range model.TagTypes {
- tl.tagMap[tagType] = make([]model.Tag, 0, 64)
- }
-
- // Organize
- for _, tag := range tl.Tags {
- tl.tagMap[tag.Type] = append(tl.tagMap[tag.Type], tag)
- }
-
- return tl.tagMap
-}
-
-// Setup sets up the page model and the base, and should
-// be run after the details have been filled in.
-func (tl *TagList) Setup(user *auth.User) {
- title := tl.Type
- if tl.Type != "" {
- title = "All"
- }
-
- tl.setupBase(user, fmt.Sprintf("%s Tags", title))
-}
diff --git a/viewmodel/userlogin.go b/viewmodel/userlogin.go
index 9701847..32eeb03 100644
--- a/viewmodel/userlogin.go
+++ b/viewmodel/userlogin.go
@@ -15,5 +15,5 @@ type UserLogin struct {
// Setup sets up the page model and the base, and should
// be run after the details have been filled in.
func (ul *UserLogin) Setup(user *auth.User) {
- ul.setupBase(user, "Login")
+ ul.setupBase(user, "Login", "/user/login")
}