Fix extends

This commit is contained in:
iacore
2024-08-24 09:13:59 +00:00
parent 822a157a6e
commit 8b5b4b6711
26 changed files with 265 additions and 261 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container">
<h1>About PixivFE</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container illust" id="checkpoint">
{{ include "components/artwork" .Illust }}
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
{{ range Artworks }}
<div class="container illust">
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container">
<h1>Discover artworks</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container error">
<h1>An error occured</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container">
<h1>Newest works from people you follow</h1>
+6 -6
View File
@@ -1,15 +1,15 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container">
{{ if isset(NoTokenData) }}
{{ if !.LoggedIn }}
<p>Not logged in. You can login <a href="/settings">here</a>.</p>
<div class="component-header">
<h2>Today's illustration rankings</h2>
<a href="/ranking?content=all">See more</a>
</div>
<div class="artwork-container-scroll">
{{ include "components/ranking-tn" NoTokenData.Contents }}
{{ include "components/ranking-tn" .NoTokenData.Contents }}
</div>
{{ else }}
@@ -23,15 +23,15 @@
<a href="/self/followingWorks">See more</a>
</div>
<div class="artwork-container-scroll">
{{ include "components/small-tn" Data.Following }}
{{ include "components/small-tn" .Data.Following }}
</div>
<br />
<h2>Recommended works</h2>
<div class="artwork-container">
{{ include "components/small-tn" Data.Recommended }}
{{ include "components/small-tn" .Data.Recommended }}
</div>
<br />
{{ range Data.RecommendByTags }}
{{ range .Data.RecommendByTags }}
<h2>Recommended illustrations tagged <a href="/tags/{{.Name}}">#{{.Name}}</a></h2>
<div class="artwork-container">
{{ include "components/small-tn" .Artworks }}
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container">
<h1>Newest works from all users</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container novel" id="checkpoint">
<div class="novel-detail">
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container">
<h1>Discover novels</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container">
<div class="vision-container">
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container illust">
<h2>{{Article.Title}}</h2>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
{{ import "components/switcher" }}
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container">
<h1>Ranking calendar ({{ ThisMonth.MonthLiteral }} {{ Year }})</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container" data-hx-boost="false">
<h1>Settings</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
{{ import "components/switcher" }}
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
{{ if Token }}
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<div class="container error">
<h1>Unauthorized</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
{{ if ! User.BackgroundImage }}
<div class="background-cover"></div>
+1 -1
View File
@@ -1,4 +1,4 @@
{{extends "layout/default.jet"}}
{{extends "layout/default.jet.html"}}
{{block body()}}
<?xml version="1.0" encoding="utf-8"?>{* <?xml-stylesheet href="/feed.xsl" type="text/xsl"?> *}
<feed xmlns="http://www.w3.org/2005/Atom">
+3 -2
View File
@@ -7,8 +7,9 @@ Then, the templating engine is decoupled from gofiber.
### Fixing current templates
gofiber doesn't mention this crucial distinction of Jet: the difference between variables (e.g. PageURL) and data (the data parameter to `Render(...)`).
If you see error like `<variable name> not found in map[...]` when visiting a page, you need to add a dot before all data member access. e.g. from `Illust` to `.Illust`.
Data access must be prefixed with a dot. `.Illust` is valid. `Illust` is a variable but not data.
gofiber doesn't mention this.
In Jet, variables are accessed without a dot (`PageURL`), while data members (the `data` parameter to `Render(...)`). are accessed with a dot in front.
Current templates use the variable style (`Illust`), but that is wrong.
+8 -4
View File
@@ -18,8 +18,10 @@ func IndexPage(c *fiber.Ctx) error {
return err
}
return c.Render("index", fiber.Map{
"Title": "Landing", "Data": works,
return Render(c, Data_index{
Title: "Landing",
Data: *works,
IsLoggedIn: true,
})
}
@@ -28,8 +30,10 @@ func IndexPage(c *fiber.Ctx) error {
if err != nil {
return err
}
return c.Render("index", fiber.Map{
"Title": "Landing", "NoTokenData": works,
return Render(c, Data_index{
Title: "Landing",
NoTokenData: works,
IsLoggedIn: false,
})
}
+84
View File
@@ -0,0 +1,84 @@
package routes
import (
"log"
"reflect"
"strings"
"codeberg.org/vnpower/pixivfe/v2/session"
"codeberg.org/vnpower/pixivfe/v2/utils"
"github.com/CloudyKit/jet/v6"
"github.com/gofiber/fiber/v2"
)
// global variable, yes.
var views *jet.Set
func InitTemplatingEngine(InDevelopment bool) {
if InDevelopment {
views = jet.NewSet(
jet.NewOSFileSystemLoader("assets/views"),
jet.InDevelopmentMode(), // disable cache
)
} else {
views = jet.NewSet(
jet.NewOSFileSystemLoader("assets/views"),
)
}
for fn_name, fn := range utils.GetTemplateFunctions() {
views.AddGlobal(fn_name, fn)
}
}
func Render[T any](c *fiber.Ctx, data T) error {
template_name, found := strings.CutPrefix(reflect.TypeFor[T]().Name(), "Data_")
if !found {
log.Panicf("struct name does not start with 'Data_': %s", template_name)
}
// Pass in values that we want to be available to all pages here
token := session.GetPixivToken(c)
pageURL := c.BaseURL() + c.OriginalURL()
cookies := map[string]string{}
for _, name := range session.AllCookieNames {
value := session.GetCookie(c, name)
cookies[string(name)] = value
}
template, err := views.GetTemplate(template_name + ".jet.html")
if err != nil {
return err
}
views.Parse(template_name + ".jet.html", template.String())
variables := jet.VarMap{}
// The middleware at line 99 in `main.go` cannot bind these values below if we use this function.
variables.Set("BaseURL", c.BaseURL())
variables.Set("OriginalURL", c.OriginalURL())
variables.Set("PageURL", pageURL)
variables.Set("LoggedIn", token != "")
variables.Set("Queries", c.Queries())
variables.Set("CookieList", cookies)
c.Context().SetContentType("text/html; charset=utf-8")
return template.Execute(c.Response().BodyWriter(), variables, data)
}
// func structToMap[T any](data T) map[string]any {
// result := map[string]any{}
// Type := reflect.TypeFor[T]()
// for i := 0; i < Type.NumField(); i += 1 {
// field := Type.Field(i)
// result[field.Name] = fieldName(data, field.Name)
// }
// return result
// }
// // assumes that the field `field_name` exists, panics otherwise
// func fieldName[T any](data T, field_name string) any {
// return reflect.ValueOf(data).FieldByName(field_name).Interface()
// }
-207
View File
@@ -1,207 +0,0 @@
package routes
import (
"log"
"reflect"
"strings"
"codeberg.org/vnpower/pixivfe/v2/core"
"codeberg.org/vnpower/pixivfe/v2/session"
"codeberg.org/vnpower/pixivfe/v2/utils"
"github.com/CloudyKit/jet/v6"
"github.com/gofiber/fiber/v2"
)
type Data_error struct {
Title string
Error error
}
type Data_about struct {
Time string
Version string
ImageProxy string
AcceptLanguage string
}
type Data_artwork struct {
Illust core.Illust // faker can't fill this
Title string
MetaDescription string
MetaImage string
MetaAuthor string
MetaAuthorID string
}
type Data_artworkMulti struct {
Artworks []core.Illust
Title string
}
type Data_userAtom struct {
URL string
Title string
User core.User
Category core.UserArtCategory
Updated string
PageLimit int
Page int
// MetaImage string
}
// below are unconverted. types may be wrong.
type Data_discovery struct {
Artworks string
Title string
Queries string
}
type Data_novelDiscovery struct {
Novels string
Title string
}
type Data_index struct {
Title string
Data string
}
type Data_newest struct {
Items string
Title string
}
type Data_novel struct {
Novel string
NovelRelated string
User string
Title string
FontType string
ViewMode string
Language string
}
type Data_unauthorized struct{}
type Data_following struct {
Title string
Mode string
Artworks string
CurPage string
Page string
}
// type Data_pixivisionindex struct {
// Data string
// }
//
// type Data_pixivisionarticle struct {
// Article string
// }
type Data_rank struct {
Title string
Page string
PageLimit int
Date string
Data string
}
type Data_rankingCalendar struct {
Title string
Render string
Mode string
Year string
MonthBefore string
MonthAfter string
ThisMonth string
}
// type Data_settings struct {
// ProxyList string
// }
//
// type Data_tag struct {
// Title string
// }
type Data_user struct {
Title string
User string
Category string
PageLimit int
Page string
MetaImage string
}
// add new types above this line
// whenever you add new types, update `TestTemplates` in render_test.go to include the type in the test
// caution: do not use pointer in Data_* struct. faker will insert nil.
// caution: do not name template file a.b.jet.html or it won't be able to be used here, since Data_a.b is not a valid identifier.
// global variable, yes.
var views *jet.Set
func InitTemplatingEngine(InDevelopment bool) {
if InDevelopment {
views = jet.NewSet(
jet.NewOSFileSystemLoader("assets/views"),
jet.InDevelopmentMode(), // disable cache
)
} else {
views = jet.NewSet(
jet.NewOSFileSystemLoader("assets/views"),
)
}
for fn_name, fn := range utils.GetTemplateFunctions() {
views.AddGlobal(fn_name, fn)
}
}
func Render[T any](c *fiber.Ctx, data T) error {
template_name, found := strings.CutPrefix(reflect.TypeFor[T]().Name(), "Data_")
if !found {
log.Panicf("struct name does not start with 'Data_': %s", template_name)
}
// Pass in values that we want to be available to all pages here
token := session.GetPixivToken(c)
pageURL := c.BaseURL() + c.OriginalURL()
cookies := map[string]string{}
for _, name := range session.AllCookieNames {
value := session.GetCookie(c, name)
cookies[string(name)] = value
}
template, err := views.GetTemplate(template_name + ".jet.html")
if err != nil {
return err
}
views.Parse(template_name + ".jet.html", template.String())
variables := jet.VarMap{}
// The middleware at line 99 in `main.go` cannot bind these values below if we use this function.
variables.Set("BaseURL", c.BaseURL())
variables.Set("OriginalURL", c.OriginalURL())
variables.Set("PageURL", pageURL)
variables.Set("LoggedIn", token != "")
variables.Set("Queries", c.Queries())
variables.Set("CookieList", cookies)
// Type := reflect.TypeFor[T]()
// for _, special_varname := range []string{"Title", "MetaAuthor", "MetaDescription", "MetaImage"} {
// _, has_field := Type.FieldByName(special_varname)
// if has_field {
// variables.Set(special_varname, FieldName(data, special_varname))
// }
// }
c.Context().SetContentType("text/html; charset=utf-8")
return template.Execute(c.Response().BodyWriter(), variables, data)
}
func StructToMap[T any](data T) map[string]any {
result := map[string]any{}
Type := reflect.TypeFor[T]()
for i := 0; i < Type.NumField(); i += 1 {
field := Type.Field(i)
result[field.Name] = FieldName(data, field.Name)
}
return result
}
// assumes that the field `field_name` exists, panics otherwise
func FieldName[T any](data T, field_name string) any {
return reflect.ValueOf(data).FieldByName(field_name).Interface()
}
+25 -23
View File
@@ -13,25 +13,25 @@ import (
)
func TestTemplates(t *testing.T) {
test[Data_error](t)
test[Data_about](t)
test[Data_artwork](t)
test[Data_artworkMulti](t)
test[Data_discovery](t)
test[Data_novelDiscovery](t)
test[Data_index](t)
test[Data_newest](t)
test[Data_novel](t)
test[Data_unauthorized](t)
test[Data_following](t)
test[Data_pixivisionindex](t)
test[Data_pixivisionarticle](t)
test[Data_rank](t)
test[Data_rankingCalendar](t)
test[Data_settings](t)
test[Data_tag](t)
test[Data_user](t)
test[Data_userAtom](t)
autoTest[Data_error](t)
autoTest[Data_about](t)
autoTest[Data_artwork](t)
autoTest[Data_artworkMulti](t)
autoTest[Data_discovery](t)
autoTest[Data_novelDiscovery](t)
autoTest[Data_index](t)
autoTest[Data_newest](t)
autoTest[Data_novel](t)
autoTest[Data_unauthorized](t)
autoTest[Data_following](t)
autoTest[Data_pixivision_index](t)
autoTest[Data_pixivision_article](t)
autoTest[Data_rank](t)
autoTest[Data_rankingCalendar](t)
autoTest[Data_settings](t)
autoTest[Data_tag](t)
autoTest[Data_user](t)
autoTest[Data_userAtom](t)
}
var engine *jet.Engine
@@ -49,16 +49,19 @@ func TestMain(m *testing.M) {
m.Run()
}
// test template
func test[T any](t *testing.T) {
// autoTest template with fake data
func autoTest[T any](t *testing.T) {
var data T
faker.FakeData(&data)
manualTest(t, data)
}
func manualTest[T any](t *testing.T, data T) {
route_name, found := strings.CutPrefix(reflect.TypeFor[T]().Name(), "Data_")
if !found {
log.Panicf("struct name does not start with 'Data_': %s", route_name)
}
bindings := StructToMap(data)
bindings := structToMap(data)
for k, v := range map[string]any{
"BaseURL": "",
@@ -78,4 +81,3 @@ func test[T any](t *testing.T) {
t.Errorf("while rendering template %s: %v", template_name, err)
}
}
+120
View File
@@ -0,0 +1,120 @@
package routes
import "codeberg.org/vnpower/pixivfe/v2/core"
type Data_error struct {
Title string
Error error
}
type Data_about struct {
Time string
Version string
ImageProxy string
AcceptLanguage string
}
type Data_artwork struct {
Illust core.Illust // faker can't fill this
Title string
MetaDescription string
MetaImage string
MetaAuthor string
MetaAuthorID string
}
type Data_artworkMulti struct {
Artworks []core.Illust
Title string
}
type Data_userAtom struct {
URL string
Title string
User core.User
Category core.UserArtCategory
Updated string
PageLimit int
Page int
// MetaImage string
}
type Data_index struct {
Title string
IsLoggedIn bool
Data core.LandingArtworks
NoTokenData core.Ranking
}
// below are unconverted. types may be wrong.
type Data_discovery struct {
Artworks string
Title string
Queries string
}
type Data_novelDiscovery struct {
Novels string
Title string
}
type Data_newest struct {
Items string
Title string
}
type Data_novel struct {
Novel string
NovelRelated string
User string
Title string
FontType string
ViewMode string
Language string
}
type Data_unauthorized struct{}
type Data_following struct {
Title string
Mode string
Artworks string
CurPage string
Page string
}
// type Data_pixivisionindex struct {
// Data string
// }
//
// type Data_pixivisionarticle struct {
// Article string
// }
type Data_rank struct {
Title string
Page string
PageLimit int
Date string
Data string
}
type Data_rankingCalendar struct {
Title string
Render string
Mode string
Year string
MonthBefore string
MonthAfter string
ThisMonth string
}
// type Data_settings struct {
// ProxyList string
// }
//
// type Data_tag struct {
// Title string
// }
type Data_user struct {
Title string
User string
Category string
PageLimit int
Page string
MetaImage string
}
// add new types above this line
// whenever you add new types, update `TestTemplates` in render_test.go to include the type in the test
// caution: do not use pointer in Data_* struct. faker will insert nil.
// caution: do not name template file a.b.jet.html or it won't be able to be used here, since Data_a.b is not a valid identifier.