diff --git a/cmd/query_gen/main.go b/cmd/query_gen/main.go index 6c45311a..9f314865 100644 --- a/cmd/query_gen/main.go +++ b/cmd/query_gen/main.go @@ -125,6 +125,7 @@ func seedTables(adapter qgen.Adapter) error { qgen.Install.SimpleInsert("settings", "name, content, type", "'megapost_min_words','1000','int'") qgen.Install.SimpleInsert("settings", "name, content, type", "'meta_desc','','html-attribute'") qgen.Install.SimpleInsert("settings", "name, content, type", "'rapid_loading','1','bool'") + qgen.Install.SimpleInsert("settings", "name, content, type", "'google_site_verify','','html-attribute'") qgen.Install.SimpleInsert("themes", "uname, default", "'cosora',1") qgen.Install.SimpleInsert("emails", "email, uid, validated", "'admin@localhost',1,1") // ? - Use a different default email or let the admin input it during installation? diff --git a/common/errors.go b/common/errors.go index 1f59b2de..6d095eac 100644 --- a/common/errors.go +++ b/common/errors.go @@ -311,6 +311,12 @@ func SecurityError(w http.ResponseWriter, r *http.Request, user User) RouteError return HandledRouteError() } +func MicroNotFound(w http.ResponseWriter, r *http.Request) RouteError { + w.WriteHeader(404) + _, _ = w.Write([]byte("file not found")) + return HandledRouteError() +} + // NotFound is used when the requested page doesn't exist // ? - Add a JSQ version of this? // ? - Add a user parameter? @@ -320,7 +326,7 @@ func NotFound(w http.ResponseWriter, r *http.Request, header *Header) RouteError // ? - Add a user parameter? func NotFoundJS(w http.ResponseWriter, r *http.Request) RouteError { - w.WriteHeader(401) + w.WriteHeader(404) writeJsonError(phrases.GetErrorPhrase("not_found_body"), w) return HandledRouteError() } diff --git a/common/files.go b/common/files.go index ac18a260..2ea51545 100644 --- a/common/files.go +++ b/common/files.go @@ -39,17 +39,6 @@ type CSSData struct { func (list SFileList) JSTmplInit() error { DebugLog("Initialising the client side templates") - var fragMap = make(map[string][][]byte) - var parseFrags = func(name string) { - fragMap[name] = tmpl.GetFrag(name) - } - parseFrags("alert") - parseFrags("forum") - parseFrags("topics_topic") - parseFrags("topic_posts") - parseFrags("topic_alt_posts") - parseFrags("paginator") - DebugLog("fragMap: ", fragMap) return filepath.Walk("./tmpl_client", func(path string, f os.FileInfo, err error) error { if f.IsDir() || strings.HasSuffix(path, "template_list.go") || strings.HasSuffix(path, "stub.go") { return nil @@ -75,7 +64,7 @@ func (list SFileList) JSTmplInit() error { } data = data[startIndex-len([]byte("func init() {")):] data = replace(data, "func ", "function ") - data = replace(data, "function init() {", "tmplInits[\""+tmplName+"\"] = ") + data = replace(data, "function init() {", "if(tmplInits===undefined) var tmplInits = {};\ntmplInits[\""+tmplName+"\"] = ") data = replace(data, " error {\n", " {\nlet out = \"\"\n") funcIndex, hasFunc := skipAllUntilCharsExist(data, 0, []byte("function Template_")) if !hasFunc { @@ -220,19 +209,23 @@ func (list SFileList) JSTmplInit() error { data = replace(data, `= }`, "= []") - fragset, ok := fragMap[shortName] - if !ok { - DebugLog("tmplName: ", tmplName) - return errors.New("couldn't find template in fragmap") + fragset := tmpl.GetFrag(shortName) + if fragset != nil { + var sfrags = []byte("let " + shortName + "_frags = [];\n") + for _, frags := range fragset { + sfrags = append(sfrags, []byte(shortName+"_frags.push(`"+string(frags)+"`);\n")...) + } + data = append(sfrags, data...) } - - var sfrags = []byte("let " + shortName + "_frags = [];\n") - for _, frags := range fragset { - sfrags = append(sfrags, []byte(shortName+"_frags.push(`"+string(frags)+"`);\n")...) - } - data = append(sfrags, data...) data = replace(data, "\n;", "\n") + for name, _ := range Themes { + if strings.HasSuffix(shortName, "_"+name) { + data = append(data, "\nlet Template_"+strings.TrimSuffix(shortName, "_"+name)+" = Template_"+shortName+";"...) + break + } + } + path = tmplName + ".js" DebugLog("js path: ", path) var ext = filepath.Ext("/tmpl_client/" + path) diff --git a/common/pages.go b/common/pages.go index 92223b43..4af4f0d4 100644 --- a/common/pages.go +++ b/common/pages.go @@ -15,8 +15,9 @@ import ( type Header struct { Title string //Title []byte // Experimenting with []byte for increased efficiency, let's avoid converting too many things to []byte, as it involves a lot of extra boilerplate - NoticeList []string - Scripts []string + NoticeList []string + Scripts []string + PreScriptsAsync []string //Preload []string Stylesheets []string Widgets PageWidgets @@ -33,18 +34,23 @@ type Header struct { Path string MetaDesc string //OGImage string - OGDesc string - LooseCSP bool - StartedAt time.Time - Elapsed1 string - Writer http.ResponseWriter - ExtData ExtData + OGDesc string + GoogSiteVerify string + LooseCSP bool + StartedAt time.Time + Elapsed1 string + Writer http.ResponseWriter + ExtData ExtData } func (header *Header) AddScript(name string) { header.Scripts = append(header.Scripts, name) } +func (header *Header) AddPreScriptAsync(name string) { + header.PreScriptsAsync = append(header.PreScriptsAsync, name) +} + /*func (header *Header) Preload(name string) { header.Preload = append(header.Preload, name) }*/ diff --git a/common/routes_common.go b/common/routes_common.go index 52c2aef4..eb36146b 100644 --- a/common/routes_common.go +++ b/common/routes_common.go @@ -150,6 +150,18 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header stats.Themes = len(Themes) stats.Reports = 0 // TODO: Do the report count. Only show open threads? + var addPreScript = func(name string) { + var tname string + if theme.OverridenMap != nil { + _, ok := theme.OverridenMap[name+".html"] + if ok { + tname = "_" + theme.Name + } + } + header.AddPreScriptAsync("template_" + name + tname + ".js") + } + addPreScript("alert") + return header, stats, nil } @@ -182,14 +194,15 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Head } header = &Header{ - Site: Site, - Settings: SettingBox.Load().(SettingMap), - Themes: Themes, - Theme: theme, - CurrentUser: *user, // ! Some things rely on this being a pointer downstream from this function - Hooks: GetHookTable(), - Zone: "frontend", - Writer: w, + Site: Site, + Settings: SettingBox.Load().(SettingMap), + Themes: Themes, + Theme: theme, + CurrentUser: *user, // ! Some things rely on this being a pointer downstream from this function + Hooks: GetHookTable(), + Zone: "frontend", + Writer: w, + GoogSiteVerify: header.Settings["google_site_verify"].(string), } if user.IsBanned { @@ -222,6 +235,22 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Head } } + var addPreScript = func(name string) { + var tname string + if theme.OverridenMap != nil { + //fmt.Printf("name %+v\n", name) + //fmt.Printf("theme.OverridenMap %+v\n", theme.OverridenMap) + _, ok := theme.OverridenMap[name+".html"] + if ok { + tname = "_" + theme.Name + } + } + header.AddPreScriptAsync("template_" + name + tname + ".js") + } + addPreScript("topics_topic") + addPreScript("paginator") + addPreScript("alert") + return header, nil } diff --git a/common/template_init.go b/common/template_init.go index 52eaedc3..0ea8b83f 100644 --- a/common/template_init.go +++ b/common/template_init.go @@ -102,14 +102,15 @@ func tmplInitUsers() (User, User, User) { func tmplInitHeaders(user User, user2 User, user3 User) (*Header, *Header, *Header) { header := &Header{ - Site: Site, - Settings: SettingBox.Load().(SettingMap), - Themes: Themes, - Theme: Themes[DefaultThemeBox.Load().(string)], - CurrentUser: user, - NoticeList: []string{"test"}, - Stylesheets: []string{"panel"}, - Scripts: []string{"whatever"}, + Site: Site, + Settings: SettingBox.Load().(SettingMap), + Themes: Themes, + Theme: Themes[DefaultThemeBox.Load().(string)], + CurrentUser: user, + NoticeList: []string{"test"}, + Stylesheets: []string{"panel.css"}, + Scripts: []string{"whatever.js"}, + PreScriptsAsync: []string{"whatever.js"}, Widgets: PageWidgets{ LeftSidebar: template.HTML("lalala"), }, @@ -168,7 +169,7 @@ func CompileTemplates() error { config.Debug = Dev.DebugMode config.SuperDebug = Dev.TemplateDebug - c := tmpl.NewCTemplateSet() + c := tmpl.NewCTemplateSet("normal") c.SetConfig(config) c.SetBaseImportMap(map[string]string{ "io": "io", @@ -189,6 +190,7 @@ func CompileTemplates() error { log.Print("Compiling the per-theme templates") for theme, tmpls := range oroots { + c.ResetLogs("normal-" + theme) c.SetThemeName(theme) c.SetPerThemeTmpls(tmpls) log.Print("theme: ", theme) @@ -366,7 +368,156 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string return nil } +// ? - Add template hooks? func CompileJSTemplates() error { + log.Print("Compiling the JS templates") + // TODO: Implement per-theme template overrides here too + var overriden = make(map[string]map[string]bool) + for _, theme := range Themes { + overriden[theme.Name] = make(map[string]bool) + log.Printf("theme.OverridenTemplates: %+v\n", theme.OverridenTemplates) + for _, override := range theme.OverridenTemplates { + overriden[theme.Name][override] = true + } + } + log.Printf("overriden: %+v\n", overriden) + + var config tmpl.CTemplateConfig + config.Minify = Config.MinifyTemplates + config.Debug = Dev.DebugMode + config.SuperDebug = Dev.TemplateDebug + config.SkipHandles = true + config.SkipTmplPtrMap = true + config.SkipInitBlock = false + config.PackageName = "tmpl" + + c := tmpl.NewCTemplateSet("js") + c.SetConfig(config) + c.SetBuildTags("!no_templategen") + c.SetOverrideTrack(overriden) + c.SetPerThemeTmpls(make(map[string]bool)) + + log.Print("Compiling the default templates") + var wg sync.WaitGroup + err := compileJSTemplates(&wg, c, "") + if err != nil { + return err + } + oroots := c.GetOverridenRoots() + log.Printf("oroots: %+v\n", oroots) + + log.Print("Compiling the per-theme templates") + for theme, tmpls := range oroots { + c.SetThemeName(theme) + c.SetPerThemeTmpls(tmpls) + log.Print("theme: ", theme) + log.Printf("perThemeTmpls: %+v\n", tmpls) + err = compileJSTemplates(&wg, c, theme) + if err != nil { + return err + } + } + var dirPrefix = "./tmpl_client/" + writeTemplateList(c, &wg, dirPrefix) + return nil +} + +func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string) error { + user, user2, user3 := tmplInitUsers() + header, _, _ := tmplInitHeaders(user, user2, user3) + now := time.Now() + var varList = make(map[string]tmpl.VarItem) + + c.SetBaseImportMap(map[string]string{ + "io": "io", + "github.com/Azareal/Gosora/common/alerts": "github.com/Azareal/Gosora/common/alerts", + }) + + // TODO: Check what sort of path is sent exactly and use it here + alertItem := alerts.AlertItem{Avatar: "", ASID: 1, Path: "/", Message: "uh oh, something happened"} + alertTmpl, err := c.Compile("alert.html", "templates/", "alerts.AlertItem", alertItem, varList) + if err != nil { + return err + } + + c.SetBaseImportMap(map[string]string{ + "io": "io", + "github.com/Azareal/Gosora/common": "github.com/Azareal/Gosora/common", + }) + // TODO: Fix the import loop so we don't have to use this hack anymore + c.SetBuildTags("!no_templategen,tmplgentopic") + + tmpls := TItemHold(make(map[string]TItem)) + + var topicsRow = &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "127.0.0.1", 1, 0, 1, 0, 1, "classname", "", &user2, "", 0, &user3, "General", "/forum/general.2"} + tmpls.AddStd("topics_topic", "common.TopicsRow", topicsRow) + + poll := Poll{ID: 1, Type: 0, Options: map[int]string{0: "Nothing", 1: "Something"}, Results: map[int]int{0: 5, 1: 2}, QuickOptions: []PollOption{ + PollOption{0, "Nothing"}, + PollOption{1, "Something"}, + }, VoteCount: 7} + avatar, microAvatar := BuildAvatar(62, "") + miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}} + topic := TopicUser{1, "blah", "Blah", "Hey there!", 62, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", "", "", 58, false, miniAttach} + var replyList []ReplyUser + // TODO: Do we really want the UID here to be zero? + avatar, microAvatar = BuildAvatar(0, "") + replyList = append(replyList, ReplyUser{0, 0, "Yo!", "Yo!", 0, "alice", "Alice", Config.DefaultGroup, now, 0, 0, avatar, microAvatar, "", 0, "", "", "", "", 0, "127.0.0.1", false, 1, 1, "", "", miniAttach}) + + varList = make(map[string]tmpl.VarItem) + header.Title = "Topic Name" + tpage := TopicPage{header, replyList, topic, &Forum{ID: 1, Name: "Hahaha"}, poll, Paginator{[]int{1}, 1, 1}} + tpage.Forum.Link = BuildForumURL(NameToSlug(tpage.Forum.Name), tpage.Forum.ID) + tmpls.AddStd("topic_posts", "common.TopicPage", tpage) + tmpls.AddStd("topic_alt_posts", "common.TopicPage", tpage) + + itemsPerPage := 25 + _, page, lastPage := PageOffset(20, 1, itemsPerPage) + pageList := Paginate(20, itemsPerPage, 5) + tmpls.AddStd("paginator", "common.Paginator", Paginator{pageList, page, lastPage}) + + var dirPrefix = "./tmpl_client/" + var writeTemplate = func(name string, content string) { + log.Print("Writing template '" + name + "'") + if content == "" { + return //log.Fatal("No content body") + } + wg.Add(1) + go func() { + tname := themeName + if tname != "" { + tname = "_" + tname + } + err := writeFile(dirPrefix+"template_"+name+tname+".go", content) + if err != nil { + log.Fatal(err) + } + wg.Done() + }() + } + + log.Print("Writing the templates") + for name, titem := range tmpls { + log.Print("Writing " + name) + varList := make(map[string]tmpl.VarItem) + tmpl, err := c.Compile(name+".html", "templates/", titem.Expects, titem.ExpectsInt, varList) + if err != nil { + return err + } + writeTemplate(name, tmpl) + } + writeTemplate("alert", alertTmpl) + /*//writeTemplate("forum", forumTmpl) + writeTemplate("topics_topic", topicListItemTmpl) + writeTemplate("topic_posts", topicPostsTmpl) + writeTemplate("topic_alt_posts", topicAltPostsTmpl) + writeTemplate("paginator", paginatorTmpl) + //writeTemplate("panel_themes_widgets_widget", panelWidgetsWidgetTmpl) + writeTemplateList(c, &wg, dirPrefix)*/ + return nil +} + +/*func CompileJSTemplates() error { log.Print("Compiling the JS templates") var config tmpl.CTemplateConfig config.Minify = Config.MinifyTemplates @@ -443,12 +594,6 @@ func CompileJSTemplates() error { return err } - /*widget := &Widget{ID: 0} - panelWidgetsWidgetTmpl, err := c.Compile("panel_themes_widgets_widget.html", "templates/", "*common.Widget", widget, varList) - if err != nil { - return err - }*/ - var dirPrefix = "./tmpl_client/" var wg sync.WaitGroup var writeTemplate = func(name string, content string) { @@ -474,9 +619,10 @@ func CompileJSTemplates() error { //writeTemplate("panel_themes_widgets_widget", panelWidgetsWidgetTmpl) writeTemplateList(c, &wg, dirPrefix) return nil -} +}*/ func getTemplateList(c *tmpl.CTemplateSet, wg *sync.WaitGroup, prefix string) string { + DebugLog("in getTemplateList") pout := "\n// nolint\nfunc init() {\n" var tFragCount = make(map[string]int) var bodyMap = make(map[string]string) //map[body]fragmentPrefix @@ -484,6 +630,8 @@ func getTemplateList(c *tmpl.CTemplateSet, wg *sync.WaitGroup, prefix string) st var tmpCount = 0 for _, frag := range c.FragOut { front := frag.TmplName + "_frags[" + strconv.Itoa(frag.Index) + "]" + DebugLog("front: ", front) + DebugLog("frag.Body: ", frag.Body) /*bodyMap, tok := tmplMap[frag.TmplName] if !tok { tmplMap[frag.TmplName] = make(map[string]string) @@ -493,9 +641,12 @@ func getTemplateList(c *tmpl.CTemplateSet, wg *sync.WaitGroup, prefix string) st if !ok { bodyMap[frag.Body] = front var bits string + DebugLog("encoding frag.Body") for _, char := range []byte(frag.Body) { if char == '\'' { bits += "'\\" + string(char) + "'," + } else if char < 32 { + bits += strconv.Itoa(int(char)) + "," } else { bits += "'" + string(char) + "'," } @@ -506,6 +657,7 @@ func getTemplateList(c *tmpl.CTemplateSet, wg *sync.WaitGroup, prefix string) st tmpCount++ //pout += front + " = []byte(`" + frag.Body + "`)\n" } else { + DebugLog("encoding cached index " + fp) pout += front + " = " + fp + "\n" } diff --git a/common/templates/minifiers.go b/common/templates/minifiers.go index 58cbf53e..a8d10120 100644 --- a/common/templates/minifiers.go +++ b/common/templates/minifiers.go @@ -6,7 +6,7 @@ import ( ) // TODO: Write unit tests for this -func minify(data string) string { +func Minify(data string) string { data = strings.Replace(data, "\t", "", -1) data = strings.Replace(data, "\v", "", -1) data = strings.Replace(data, "\n", "", -1) @@ -19,7 +19,7 @@ func minify(data string) string { // TODO: Handle CSS nested in {{end}} diff --git a/templates/panel_pages.html b/templates/panel_pages.html index 510df7e6..1f55b10e 100644 --- a/templates/panel_pages.html +++ b/templates/panel_pages.html @@ -5,7 +5,7 @@

{{lang "panel_pages_head"}}

-
+
{{range .ItemList}}
{{.Title}} [{{.Name}}] diff --git a/templates/profile.html b/templates/profile.html index eb30f7a3..23b5b136 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -51,6 +51,7 @@
{{end}} {{end}} diff --git a/themes/cosora/public/profile.css b/themes/cosora/public/profile.css index e69de29b..fbaa7aaf 100644 --- a/themes/cosora/public/profile.css +++ b/themes/cosora/public/profile.css @@ -0,0 +1,8 @@ +.colline { + border: 1px solid var(--element-border-color); + border-bottom: 2px solid var(--element-border-color); + background-color: var(--element-background-color); + padding: 8px; + margin-left: 16px; + margin-bottom: 12px; +} \ No newline at end of file diff --git a/themes/nox/overrides/topics_topic.html b/themes/nox/overrides/topics_topic.html new file mode 100644 index 00000000..488f3695 --- /dev/null +++ b/themes/nox/overrides/topics_topic.html @@ -0,0 +1,25 @@ +
+
+ {{.Creator.Name}}'s Avatar + + {{.Title}}{{if .ForumName}}-{{.ForumName}}{{end}} +
{{.Creator.Name}} +
+
+
+
+ {{.PostCount}} {{lang "topic_list.replies_suffix"}} + {{.LikeCount}} {{lang "topic_list.likes_suffix"}} + {{.ViewCount}} {{lang "topic_list.views_suffix"}} +
+
+ +
\ No newline at end of file diff --git a/themes/nox/public/acc_panel_common.css b/themes/nox/public/acc_panel_common.css index 94aed3c0..5659c587 100644 --- a/themes/nox/public/acc_panel_common.css +++ b/themes/nox/public/acc_panel_common.css @@ -1,3 +1,6 @@ +#main { + max-width: none; +} .colstack_left { width: 200px; padding-bottom: 6px; diff --git a/themes/nox/public/main.css b/themes/nox/public/main.css index b8f08d1f..40419c80 100644 --- a/themes/nox/public/main.css +++ b/themes/nox/public/main.css @@ -209,6 +209,8 @@ li a { } .filter_item a { color: #BBBBBB; + text-overflow: ellipsis; + overflow: hidden; } .colstack_right .colstack_item:not(.colstack_head):not(.rowhead) .rowitem:not(:last-child) { margin-bottom: 8px; @@ -512,8 +514,9 @@ h2 { text-overflow: ellipsis; overflow: hidden; } -.topic_inner_left .parent_forum { - display: none; /* Comment this until we figure out how to make it work */ +.parent_forum_sep { + margin-left: 6px; + margin-right: 6px; } .topic_right_inside { display: flex; @@ -1176,6 +1179,9 @@ input[type=checkbox]:checked + label .sel { .topic_list_title_block .mod_opt a:before { content: "{{lang "topic_list.moderate_short" . }}"; } + .topic_inner_left .parent_forum, .parent_forum_sep { + display: none; + } } @media(max-width: 601px) { @@ -1274,6 +1280,9 @@ input[type=checkbox]:checked + label .sel { .menu_profile { display: none; } + #main { + max-width: calc(100% - 180px); + } } @media(max-width: 850px) { @@ -1327,4 +1336,4 @@ input[type=checkbox]:checked + label .sel { .user_box { width: 200px; } -} +} \ No newline at end of file diff --git a/themes/nox/public/panel.css b/themes/nox/public/panel.css index 78c8bd3d..019a9bff 100644 --- a/themes/nox/public/panel.css +++ b/themes/nox/public/panel.css @@ -165,6 +165,8 @@ button, .formbutton, .panel_right_button:not(.has_inner_button), #panel_users .p border-radius: 5px; padding-left: 5px; padding: 12px; + overflow: hidden; + text-overflow: ellipsis; } #panel_settings.rowlist.bgavatars.micro_grid, .micro_grid { grid-gap: 24px; diff --git a/themes/nox/public/profile.css b/themes/nox/public/profile.css index 2ba11033..a1090337 100644 --- a/themes/nox/public/profile.css +++ b/themes/nox/public/profile.css @@ -1,3 +1,6 @@ +#main { + max-width: none; +} #profile_left_lane { margin-right: 24px; } diff --git a/themes/tempra-simple/public/main.css b/themes/tempra-simple/public/main.css index c887f899..e9ea591b 100644 --- a/themes/tempra-simple/public/main.css +++ b/themes/tempra-simple/public/main.css @@ -168,6 +168,9 @@ li a { .rowmenu { border: 1px solid hsl(0, 0%, 80%); } +.rowmenu > div:not(:last-child) { + border-bottom: 1px solid hsl(0, 0%, 80%); +} .rowsmall { font-size: 12px; } diff --git a/themes/tempra-simple/public/profile.css b/themes/tempra-simple/public/profile.css index e69de29b..792c3056 100644 --- a/themes/tempra-simple/public/profile.css +++ b/themes/tempra-simple/public/profile.css @@ -0,0 +1,9 @@ +.sidebar { + display: none; +} +.colline { + border-left: 1px solid hsl(0, 0%, 80%); + padding: 10px; + border-right: 1px solid hsl(0, 0%, 80%); + background-color: white; +} \ No newline at end of file