Added the theme system.

You can now switch between themes in the Control Panel.
The Alternate Post Layout teased in various screenshots and bits of inaccessible code is now the Tempra Conflux theme, while the original post layout is the Tempa Simple theme.
Dramatically increased the speed at which the static files are served.
Added a benchmark for static files.
Eliminated the name parameter in various custom page structs.
Added the TopicsPage struct for the /topics/ route.
Added the ForumPage struct for the /forum/{id} route.
Added the ForumsPage struct for the /forums/ route.
The static file route now serves 404s when a file doesn't exist instead of nearly crashing the server.
Reduced the number of unnecessary allocations on some of the routes.
Added gradients to Tempra Conflux.
Added position: sticky; to the userinfo blocks in Tempra Conflux.
Added a notice on the generated template files.
This commit is contained in:
Azareal 2017-01-01 15:45:43 +00:00
parent bcaa646f68
commit e47450d372
39 changed files with 1187 additions and 167 deletions

View File

@ -99,8 +99,15 @@ CREATE TABLE `plugins`(
unique(`uname`) unique(`uname`)
); );
CREATE TABLE `themes`(
`uname` varchar(200) not null,
`default` tinyint DEFAULT 0 not null,
unique(`uname`)
);
INSERT INTO settings(`name`,`content`,`type`) VALUES ('url_tags','1','bool'); INSERT INTO settings(`name`,`content`,`type`) VALUES ('url_tags','1','bool');
INSERT INTO settings(`name`,`content`,`type`,`constraints`) VALUES ('activation_type','1','list','1-3',); INSERT INTO settings(`name`,`content`,`type`,`constraints`) VALUES ('activation_type','1','list','1-3',);
INSERT INTO themes(`uname`,`default`) VALUES ('tempra-simple',1);
INSERT INTO users(`name`,`email`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`) INSERT INTO users(`name`,`email`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`)
VALUES ('Admin','admin@localhost',1,1,NOW(),NOW(),''); VALUES ('Admin','admin@localhost',1,1,NOW(),NOW(),'');
@ -118,6 +125,7 @@ EditUserGroupSuperMod
EditUserGroupAdmin EditUserGroupAdmin
ManageForums ManageForums
EditSettings EditSettings
ManageThemes
ManagePlugins ManagePlugins
ViewIPs ViewIPs
@ -132,11 +140,11 @@ PinTopic
CloseTopic CloseTopic
*/ */
INSERT INTO users_groups(`name`,`permissions`,`active`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManagePlugins":true,"ViewIPs":true,"ViewTopic":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,1,1,"Admin"); INSERT INTO users_groups(`name`,`permissions`,`active`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewIPs":true,"ViewTopic":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,1,1,"Admin");
INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":true,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":true,"ViewTopic":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,"Mod"); INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":true,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManageThemes":false,"ManagePlugins":false,"ViewIPs":true,"ViewTopic":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,"Mod");
INSERT INTO users_groups(`name`,`permissions`) VALUES ('Member','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":true,"EditTopic":false,"DeleteTopic":false,"CreateReply":true,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}'); INSERT INTO users_groups(`name`,`permissions`) VALUES ('Member','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManageThemes":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":true,"EditTopic":false,"DeleteTopic":false,"CreateReply":true,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}');
INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Banned','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":false,"EditTopic":false,"DeleteTopic":false,"CreateReply":false,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}',1); INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Banned','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManageThemes":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":false,"EditTopic":false,"DeleteTopic":false,"CreateReply":false,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}',1);
INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Awaiting Activation','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":false,"EditTopic":false,"DeleteTopic":false,"CreateReply":false,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}'); INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Awaiting Activation','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManageThemes":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":false,"EditTopic":false,"DeleteTopic":false,"CreateReply":false,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}');
INSERT INTO forums(`name`,`lastTopicTime`) VALUES ('General',NOW()); INSERT INTO forums(`name`,`lastTopicTime`) VALUES ('General',NOW());
INSERT INTO topics(`title`,`content`,`createdAt`,`lastReplyAt`,`createdBy`,`parentID`) INSERT INTO topics(`title`,`content`,`createdAt`,`lastReplyAt`,`createdBy`,`parentID`)

View File

@ -0,0 +1,19 @@
{
"Name": "tempra-simple",
"FriendlyName": "Tempra Simple",
"Version": "0.0.1",
"Creator": "Azareal",
"Settings": {
"PostLayout": {
"FriendlyName":"Post Layout",
"Options": ["Compact","Alternate"]
}
},
"Templates": [
{
"Name": "topic",
"Source": "topic_alt",
"When": "PostLayout=Alternate"
}
]
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" ?>
<theme>
<name>tempra-simple</name>
<friendlyName>Tempra Simple</friendlyName>
<version>0.0.1</version>
<creator url="http://github.com/Azareal">Azareal</creator>
<settings>
<name>PostLayout</name>
<friendlyName>Post Layout</name>
<options>
<option>Compact</option>
<option>Alternate</option>
</options>
</settings>
<templates>
<template name="topic" src="topic_alt" when="PostLayout=Alternate"></template>
</templates>
</theme>

View File

@ -1,5 +1,6 @@
/* Copyright Azareal 2016 - 2017 */ /* Copyright Azareal 2016 - 2017 */
package main package main
import "log"
var plugins map[string]Plugin = make(map[string]Plugin) var plugins map[string]Plugin = make(map[string]Plugin)
var hooks map[string]func(interface{})interface{} = make(map[string]func(interface{})interface{}) var hooks map[string]func(interface{})interface{} = make(map[string]func(interface{})interface{})
@ -24,6 +25,16 @@ type Plugin struct
hooks[name] = handler hooks[name] = handler
}*/ }*/
func init_plugins() {
for name, body := range plugins {
log.Print("Added plugin " + name)
if body.Active {
log.Print("Initialised plugin " + name)
plugins[name].Init()
}
}
}
func add_hook(name string, handler interface{}) { func add_hook(name string, handler interface{}) {
switch h := handler.(type) { switch h := handler.(type) {
case func(interface{})interface{}: case func(interface{})interface{}:

View File

@ -31,8 +31,8 @@ func BenchmarkTopicTemplate(b *testing.B) {
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""})
tpage := TopicPage{"Topic Blah","topic",user,noticeList,replyList,topic,false} tpage := TopicPage{"Topic Blah",user,noticeList,replyList,topic,false}
tpage2 := TopicPage{"Topic Blah","topic",admin,noticeList,replyList,topic,false} tpage2 := TopicPage{"Topic Blah",admin,noticeList,replyList,topic,false}
w := ioutil.Discard w := ioutil.Discard
b.Run("compiled_useradmin", func(b *testing.B) { b.Run("compiled_useradmin", func(b *testing.B) {
@ -65,7 +65,7 @@ func BenchmarkTopicsTemplate(b *testing.B) {
var noticeList map[int]string = make(map[int]string) var noticeList map[int]string = make(map[int]string)
noticeList[0] = "test" noticeList[0] = "test"
var topicList []interface{} var topicList []TopicUser
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""})
@ -77,8 +77,8 @@ func BenchmarkTopicsTemplate(b *testing.B) {
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""})
tpage := Page{"Topic Blah","topic",user,noticeList,topicList,0} tpage := TopicsPage{"Topic Blah",user,noticeList,topicList,0}
tpage2 := Page{"Topic Blah","topic",admin,noticeList,topicList,0} tpage2 := TopicsPage{"Topic Blah",admin,noticeList,topicList,0}
w := ioutil.Discard w := ioutil.Discard
b.Run("compiled_useradmin", func(b *testing.B) { b.Run("compiled_useradmin", func(b *testing.B) {
@ -138,6 +138,10 @@ func BenchmarkRoute(b *testing.B) {
forums_req_admin.AddCookie(&admin_session_cookie) forums_req_admin.AddCookie(&admin_session_cookie)
forums_handler := http.HandlerFunc(route_forums) forums_handler := http.HandlerFunc(route_forums)
static_w := httptest.NewRecorder()
static_req := httptest.NewRequest("get","/static/global.js",bytes.NewReader(nil))
static_handler := http.HandlerFunc(route_static)
debug = false debug = false
nogrouplog = true nogrouplog = true
@ -146,16 +150,18 @@ func BenchmarkRoute(b *testing.B) {
log.SetOutput(discard) log.SetOutput(discard)
var err error var err error
init_database(err); init_database(err)
external_sites["YT"] = "https://www.youtube.com/" external_sites["YT"] = "https://www.youtube.com/"
hooks["trow_assign"] = nil hooks["trow_assign"] = nil
hooks["rrow_assign"] = nil hooks["rrow_assign"] = nil
init_plugins()
for name, body := range plugins { b.Run("static_files", func(b *testing.B) {
if body.Active { for i := 0; i < b.N; i++ {
plugins[name].Init() static_w.Body.Reset()
static_handler.ServeHTTP(static_w,static_req)
} }
} })
b.Run("topic_admin", func(b *testing.B) { b.Run("topic_admin", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

Binary file not shown.

View File

@ -30,6 +30,7 @@ type Perms struct
EditUserGroupAdmin bool EditUserGroupAdmin bool
ManageForums bool // This could be local, albeit limited for per-forum managers ManageForums bool // This could be local, albeit limited for per-forum managers
EditSettings bool EditSettings bool
ManageThemes bool
ManagePlugins bool ManagePlugins bool
ViewIPs bool ViewIPs bool
@ -86,6 +87,7 @@ func init() {
EditUserGroupAdmin: true, EditUserGroupAdmin: true,
ManageForums: true, ManageForums: true,
EditSettings: true, EditSettings: true,
ManageThemes: true,
ManagePlugins: true, ManagePlugins: true,
ViewIPs: true, ViewIPs: true,

BIN
images/bench_round3.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

BIN
images/panel-theme-list.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

53
main.go
View File

@ -31,52 +31,54 @@ var external_sites map[string]string = make(map[string]string)
var groups map[int]Group = make(map[int]Group) var groups map[int]Group = make(map[int]Group)
var forums map[int]Forum = make(map[int]Forum) var forums map[int]Forum = make(map[int]Forum)
var static_files map[string]SFile = make(map[string]SFile) var static_files map[string]SFile = make(map[string]SFile)
var ctemplates []string
var template_topic_handle func(TopicPage,io.Writer) = nil var template_topic_handle func(TopicPage,io.Writer) = nil
var template_topic_origin_handle func(TopicPage,io.Writer) = nil
var template_topic_alt_handle func(TopicPage,io.Writer) = nil var template_topic_alt_handle func(TopicPage,io.Writer) = nil
var template_topics_handle func(Page,io.Writer) = nil var template_topics_handle func(TopicsPage,io.Writer) = nil
var template_forum_handle func(Page,io.Writer) = nil var template_forum_handle func(ForumPage,io.Writer) = nil
var template_forums_handle func(Page,io.Writer) = nil var template_forums_handle func(ForumsPage,io.Writer) = nil
var template_profile_handle func(ProfilePage,io.Writer) = nil var template_profile_handle func(ProfilePage,io.Writer) = nil
func compile_templates() { func compile_templates() {
var c CTemplateSet var c CTemplateSet
user := User{0,"","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} user := User{62,"","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""}
var noticeList map[int]string = make(map[int]string) var noticeList map[int]string = make(map[int]string)
noticeList[0] = "test" noticeList[0] = "test"
log.Print("Compiling the templates") log.Print("Compiling the templates")
topic := TopicUser{0,"",template.HTML(""),0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""} topic := TopicUser{1,"Blah",template.HTML("Hey there!"),0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""}
var replyList []Reply var replyList []Reply
replyList = append(replyList, Reply{0,0,"",template.HTML(""),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"",template.HTML("Yo!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""})
var varList map[string]VarItem = make(map[string]VarItem) var varList map[string]VarItem = make(map[string]VarItem)
tpage := TopicPage{"Title","name",user,noticeList,replyList,topic,false} tpage := TopicPage{"Title",user,noticeList,replyList,topic,false}
topic_id_tmpl := c.compile_template("topic.html","templates/","TopicPage", tpage, varList) topic_id_tmpl := c.compile_template("topic.html","templates/","TopicPage", tpage, varList)
topic_id_alt_tmpl := c.compile_template("topic_alt.html","templates/","TopicPage", tpage, varList) topic_id_alt_tmpl := c.compile_template("topic_alt.html","templates/","TopicPage", tpage, varList)
varList = make(map[string]VarItem) varList = make(map[string]VarItem)
ppage := ProfilePage{"Title",user,noticeList,replyList,user,false} ppage := ProfilePage{"User 526",user,noticeList,replyList,user,false}
profile_tmpl := c.compile_template("profile.html","templates/","ProfilePage", ppage, varList) profile_tmpl := c.compile_template("profile.html","templates/","ProfilePage", ppage, varList)
var forumList []interface{} var forumList []Forum
for _, forum := range forums { for _, forum := range forums {
if forum.Active { if forum.Active {
forumList = append(forumList, forum) forumList = append(forumList, forum)
} }
} }
varList = make(map[string]VarItem) varList = make(map[string]VarItem)
pi := Page{"Forum List","forums",user,noticeList,forumList,0} forums_page := ForumsPage{"Forum List",user,noticeList,forumList,0}
forums_tmpl := c.compile_template("forums.html","templates/","Page", pi, varList) forums_tmpl := c.compile_template("forums.html","templates/","ForumsPage", forums_page, varList)
var topicList []interface{} var topicList []TopicUser
topicList = append(topicList, TopicUser{1,"Topic Title","The topic content.",1,false,false,"",1,"open","Admin","","",0,"","","",""}) topicList = append(topicList, TopicUser{1,"Topic Title","The topic content.",1,false,false,"",1,"open","Admin","","",0,"","","",""})
pi = Page{"Topic List","topics",user,noticeList,topicList,""} topics_page := TopicsPage{"Topic List",user,noticeList,topicList,""}
topics_tmpl := c.compile_template("topics.html","templates/","Page", pi, varList) topics_tmpl := c.compile_template("topics.html","templates/","TopicsPage", topics_page, varList)
//topics_tmpl := c.compile_template("topics.html","templates/","Page", pi, varList)
pi = Page{"General Forum","forum",user,noticeList,topicList,"There aren't any topics in this forum yet."} forum_page := ForumPage{"General Forum",user,noticeList,topicList,"There aren't any topics in this forum yet."}
forum_tmpl := c.compile_template("forum.html","templates/","Page", pi, varList) forum_tmpl := c.compile_template("forum.html","templates/","ForumPage", forum_page, varList)
log.Print("Writing the templates") log.Print("Writing the templates")
write_template("topic", topic_id_tmpl) write_template("topic", topic_id_tmpl)
@ -102,8 +104,9 @@ func write_template(name string, content string) {
} }
func main(){ func main(){
init_themes()
var err error var err error
init_database(err); init_database(err)
compile_templates() compile_templates()
log.Print("Loading the static files.") log.Print("Loading the static files.")
@ -132,19 +135,11 @@ func main(){
hooks["rrow_assign"] = nil hooks["rrow_assign"] = nil
templates.ParseGlob("pages/*") templates.ParseGlob("pages/*")
for name, body := range plugins { init_plugins()
log.Print("Added plugin " + name)
if body.Active {
log.Print("Initialised plugin " + name)
plugins[name].Init()
}
}
// In a directory to stop it clashing with the other paths // In a directory to stop it clashing with the other paths
http.HandleFunc("/static/", route_static) http.HandleFunc("/static/", route_static)
//http.HandleFunc("/static/", route_fstatic)
//fs_p := http.FileServer(http.Dir("./public"))
//http.Handle("/static/", http.StripPrefix("/static/",fs_p))
fs_u := http.FileServer(http.Dir("./uploads")) fs_u := http.FileServer(http.Dir("./uploads"))
http.Handle("/uploads/", http.StripPrefix("/uploads/",fs_u)) http.Handle("/uploads/", http.StripPrefix("/uploads/",fs_u))
@ -205,6 +200,8 @@ func main(){
http.HandleFunc("/panel/settings/", route_panel_settings) http.HandleFunc("/panel/settings/", route_panel_settings)
http.HandleFunc("/panel/settings/edit/", route_panel_setting) http.HandleFunc("/panel/settings/edit/", route_panel_setting)
http.HandleFunc("/panel/settings/edit/submit/", route_panel_setting_edit) http.HandleFunc("/panel/settings/edit/submit/", route_panel_setting_edit)
http.HandleFunc("/panel/themes/", route_panel_themes)
http.HandleFunc("/panel/themes/default/", route_panel_themes_default)
http.HandleFunc("/panel/plugins/", route_panel_plugins) http.HandleFunc("/panel/plugins/", route_panel_plugins)
http.HandleFunc("/panel/plugins/activate/", route_panel_plugins_activate) http.HandleFunc("/panel/plugins/activate/", route_panel_plugins_activate)
http.HandleFunc("/panel/plugins/deactivate/", route_panel_plugins_deactivate) http.HandleFunc("/panel/plugins/deactivate/", route_panel_plugins_deactivate)

View File

@ -42,8 +42,6 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
var is_closed bool var is_closed bool
if topic_status == "closed" { if topic_status == "closed" {
is_closed = true is_closed = true
} else {
is_closed = false
} }
topic_content := html.EscapeString(r.PostFormValue("topic_content")) topic_content := html.EscapeString(r.PostFormValue("topic_content"))
@ -910,7 +908,6 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user) NoPermissions(w,r,user)
return return
} }
if r.FormValue("session") != user.Session { if r.FormValue("session") != user.Session {
SecurityError(w,r,user) SecurityError(w,r,user)
return return
@ -1243,3 +1240,95 @@ func route_panel_groups(w http.ResponseWriter, r *http.Request){
pi := Page{"Group Manager","panel-groups",user,noticeList,groupList,0} pi := Page{"Group Manager","panel-groups",user,noticeList,groupList,0}
templates.ExecuteTemplate(w,"panel-groups.html", pi) templates.ExecuteTemplate(w,"panel-groups.html", pi)
} }
func route_panel_themes(w http.ResponseWriter, r *http.Request){
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Is_Super_Mod || !user.Perms.ManageThemes {
NoPermissions(w,r,user)
return
}
var themeList []interface{}
for _, theme := range themes {
themeList = append(themeList, theme)
}
pi := Page{"Theme Manager","panel-themes",user,noticeList,themeList,0}
templates.ExecuteTemplate(w,"panel-themes.html", pi)
}
func route_panel_themes_default(w http.ResponseWriter, r *http.Request){
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Super_Mod || !user.Perms.ManageThemes {
NoPermissions(w,r,user)
return
}
if r.FormValue("session") != user.Session {
SecurityError(w,r,user)
return
}
uname := r.URL.Path[len("/panel/themes/default/"):]
theme, ok := themes[uname]
if !ok {
LocalError("The theme isn't registered in the system",w,r,user)
return
}
var isDefault bool
err := db.QueryRow("SELECT `default` from `themes` where `uname` = ?", uname).Scan(&isDefault)
if err != nil && err != sql.ErrNoRows {
InternalError(err,w,r,user)
return
}
has_theme := err != sql.ErrNoRows
if has_theme {
if isDefault {
LocalError("The theme is already active",w,r,user)
return
}
_, err = update_theme_stmt.Exec(1, uname)
if err != nil {
InternalError(err,w,r,user)
return
}
} else {
_, err := add_theme_stmt.Exec(uname,1)
if err != nil {
InternalError(err,w,r,user)
return
}
}
_, err = update_theme_stmt.Exec(0, defaultTheme)
if err != nil {
InternalError(err,w,r,user)
return
}
log.Print("Setting theme '" + theme.Name + "' as the default theme")
theme.Active = true
themes[uname] = theme
dTheme, ok := themes[defaultTheme]
if !ok {
log.Fatal("The default theme is missing")
return
}
dTheme.Active = false
themes[defaultTheme] = dTheme
defaultTheme = uname
reset_template_overrides()
add_theme_static_files(uname)
map_theme_templates(theme)
http.Redirect(w,r,"/panel/themes/",http.StatusSeeOther)
}

View File

@ -42,6 +42,8 @@ var update_setting_stmt *sql.Stmt
var add_plugin_stmt *sql.Stmt var add_plugin_stmt *sql.Stmt
var update_plugin_stmt *sql.Stmt var update_plugin_stmt *sql.Stmt
var update_user_stmt *sql.Stmt var update_user_stmt *sql.Stmt
var add_theme_stmt *sql.Stmt
var update_theme_stmt *sql.Stmt
func init_database(err error) { func init_database(err error) {
if(dbpassword != ""){ if(dbpassword != ""){
@ -253,6 +255,18 @@ func init_database(err error) {
log.Fatal(err) log.Fatal(err)
} }
log.Print("Preparing add_theme statement.")
add_theme_stmt, err = db.Prepare("INSERT INTO `themes`(`uname`,`default`) VALUES(?,?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_theme statement.")
update_theme_stmt, err = db.Prepare("UPDATE `themes` SET `default` = ? WHERE `uname` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_user statement.") log.Print("Preparing update_user statement.")
update_user_stmt, err = db.Prepare("UPDATE `users` SET `name` = ?, `email` = ?, `group` = ? WHERE `uid` = ?") update_user_stmt, err = db.Prepare("UPDATE `users` SET `name` = ?, `email` = ?, `group` = ? WHERE `uid` = ?")
if err != nil { if err != nil {
@ -381,4 +395,42 @@ func init_database(err error) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Print("Loading the themes.")
rows, err = db.Query("SELECT `uname`, `default` FROM `themes`")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var defaultThemeSwitch bool
for rows.Next() {
err := rows.Scan(&uname, &defaultThemeSwitch)
if err != nil {
log.Fatal(err)
}
// Was the theme deleted at some point?
theme, ok := themes[uname]
if !ok {
continue
}
if defaultThemeSwitch {
log.Print("Loading the theme '" + theme.Name + "'")
theme.Active = true
defaultTheme = uname
add_theme_static_files(uname)
map_theme_templates(theme)
} else {
theme.Active = false
}
themes[uname] = theme
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
} }

View File

@ -15,7 +15,6 @@ type Page struct
type TopicPage struct type TopicPage struct
{ {
Title string Title string
Name string
CurrentUser User CurrentUser User
NoticeList map[int]string NoticeList map[int]string
ItemList []Reply ItemList []Reply
@ -23,6 +22,33 @@ type TopicPage struct
ExtData interface{} ExtData interface{}
} }
type TopicsPage struct
{
Title string
CurrentUser User
NoticeList map[int]string
ItemList []TopicUser
ExtData interface{}
}
type ForumPage struct
{
Title string
CurrentUser User
NoticeList map[int]string
ItemList []TopicUser
ExtData interface{}
}
type ForumsPage struct
{
Title string
CurrentUser User
NoticeList map[int]string
ItemList []Forum
ExtData interface{}
}
type ProfilePage struct type ProfilePage struct
{ {
Title string Title string
@ -36,7 +62,6 @@ type ProfilePage struct
type PageSimple struct type PageSimple struct
{ {
Title string Title string
Name string
Something interface{} Something interface{}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

108
routes.go
View File

@ -24,18 +24,27 @@ var nList map[int]string
// GET functions // GET functions
func route_static(w http.ResponseWriter, r *http.Request){ func route_static(w http.ResponseWriter, r *http.Request){
//name := r.URL.Path[len("/static/"):] //name := r.URL.Path[len("/static/"):]
if t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && static_files[r.URL.Path].Info.ModTime().Before(t.Add(1*time.Second)) { //log.Print("Outputting static file '" + r.URL.Path + "'")
file, ok := static_files[r.URL.Path]
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
// Surely, there's a more efficient way of doing this?
if t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && file.Info.ModTime().Before(t.Add(1 * time.Second)) {
w.WriteHeader(http.StatusNotModified) w.WriteHeader(http.StatusNotModified)
return return
} }
h := w.Header() h := w.Header()
h.Set("Last-Modified", static_files[r.URL.Path].FormattedModTime) h.Set("Last-Modified", file.FormattedModTime)
h.Set("Content-Type", static_files[r.URL.Path].Mimetype) h.Set("Content-Type", file.Mimetype)
h.Set("Content-Length", strconv.FormatInt(static_files[r.URL.Path].Length, 10)) h.Set("Content-Length", strconv.FormatInt(file.Length, 10)) // Avoid doing a type conversion every time?
//http.ServeContent(w,r,r.URL.Path,static_files[r.URL.Path].Info.ModTime(),static_files[r.URL.Path]) //http.ServeContent(w,r,r.URL.Path,file.Info.ModTime(),file)
//w.Write(static_files[r.URL.Path].Data) //w.Write(file.Data)
io.Copy(w, bytes.NewReader(static_files[r.URL.Path].Data)) io.Copy(w, bytes.NewReader(file.Data)) // Use w.Write instead?
//io.CopyN(w, bytes.NewReader(static_files[r.URL.Path].Data), static_files[r.URL.Path].Length) //io.CopyN(w, bytes.NewReader(file.Data), static_files[r.URL.Path].Length)
} }
func route_fstatic(w http.ResponseWriter, r *http.Request){ func route_fstatic(w http.ResponseWriter, r *http.Request){
@ -83,21 +92,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
return return
}*/ }*/
var( var topicList []TopicUser
topicList []interface{}
tid int
title string
content string
createdBy int
is_closed bool
sticky bool
createdAt string
parentID int
status string
name string
avatar string
)
rows, err := get_topic_list_stmt.Query() rows, err := get_topic_list_stmt.Query()
if err != nil { if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
@ -105,27 +100,27 @@ func route_topics(w http.ResponseWriter, r *http.Request){
} }
defer rows.Close() defer rows.Close()
topicItem := TopicUser{ID: 0,}
for rows.Next() { for rows.Next() {
err := rows.Scan(&tid, &title, &content, &createdBy, &is_closed, &sticky, &createdAt, &parentID, &name, &avatar) err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.ParentID, &topicItem.CreatedByName, &topicItem.Avatar)
if err != nil { if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
} }
if is_closed { if topicItem.Is_Closed {
status = "closed" topicItem.Status = "shut"
} else { } else {
status = "open" topicItem.Status = "open"
} }
if avatar != "" { if topicItem.Avatar != "" {
if avatar[0] == '.' { if topicItem.Avatar[0] == '.' {
avatar = "/uploads/avatar_" + strconv.Itoa(createdBy) + avatar topicItem.Avatar = "/uploads/avatar_" + strconv.Itoa(topicItem.CreatedBy) + topicItem.Avatar
} }
} else { } else {
avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(createdBy),1) topicItem.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(topicItem.CreatedBy),1)
} }
topicItem := TopicUser{tid,title,content,createdBy,is_closed,sticky, createdAt,parentID,status,name,avatar,"",0,"","","",""}
if hooks["trow_assign"] != nil { if hooks["trow_assign"] != nil {
topicItem = run_hook("trow_assign", topicItem).(TopicUser) topicItem = run_hook("trow_assign", topicItem).(TopicUser)
} }
@ -137,7 +132,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
return return
} }
pi := Page{"Topic List","topics",user,noticeList,topicList,0} pi := TopicsPage{"Topic List",user,noticeList,topicList,0}
if template_topics_handle != nil { if template_topics_handle != nil {
template_topics_handle(pi,w) template_topics_handle(pi,w)
} else { } else {
@ -154,20 +149,7 @@ func route_forum(w http.ResponseWriter, r *http.Request){
return return
} }
var( var topicList []TopicUser
topicList []interface{}
tid int
title string
content string
createdBy int
is_closed bool
sticky bool
createdAt string
parentID int
status string
name string
avatar string
)
fid, err := strconv.Atoi(r.URL.Path[len("/forum/"):]) fid, err := strconv.Atoi(r.URL.Path[len("/forum/"):])
if err != nil { if err != nil {
@ -192,27 +174,27 @@ func route_forum(w http.ResponseWriter, r *http.Request){
} }
defer rows.Close() defer rows.Close()
topicItem := TopicUser{ID: 0}
for rows.Next() { for rows.Next() {
err := rows.Scan(&tid, &title, &content, &createdBy, &is_closed, &sticky, &createdAt, &parentID, &name, &avatar) err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.ParentID, &topicItem.CreatedByName, &topicItem.Avatar)
if err != nil { if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
} }
if is_closed { if topicItem.Is_Closed {
status = "closed" topicItem.Status = "shut"
} else { } else {
status = "open" topicItem.Status = "open"
} }
if avatar != "" { if topicItem.Avatar != "" {
if avatar[0] == '.' { if topicItem.Avatar[0] == '.' {
avatar = "/uploads/avatar_" + strconv.Itoa(createdBy) + avatar topicItem.Avatar = "/uploads/avatar_" + strconv.Itoa(topicItem.CreatedBy) + topicItem.Avatar
} }
} else { } else {
avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(createdBy),1) topicItem.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(topicItem.CreatedBy),1)
} }
topicItem := TopicUser{tid,title,content,createdBy,is_closed,sticky,createdAt,parentID,status,name,avatar,"",0,"","","",""}
if hooks["trow_assign"] != nil { if hooks["trow_assign"] != nil {
topicItem = run_hook("trow_assign", topicItem).(TopicUser) topicItem = run_hook("trow_assign", topicItem).(TopicUser)
} }
@ -224,7 +206,7 @@ func route_forum(w http.ResponseWriter, r *http.Request){
return return
} }
pi := Page{forums[fid].Name,"forum",user,noticeList,topicList,0} pi := ForumPage{forums[fid].Name,user,noticeList,topicList,0}
if template_forum_handle != nil { if template_forum_handle != nil {
template_forum_handle(pi,w) template_forum_handle(pi,w)
} else { } else {
@ -241,14 +223,14 @@ func route_forums(w http.ResponseWriter, r *http.Request){
return return
} }
var forumList []interface{} var forumList []Forum
for _, forum := range forums { for _, forum := range forums {
if forum.Active { if forum.Active {
forumList = append(forumList, forum) forumList = append(forumList, forum)
} }
} }
pi := Page{"Forum List","forums",user,noticeList,forumList,0} pi := ForumsPage{"Forum List",user,noticeList,forumList,0}
if template_forums_handle != nil { if template_forums_handle != nil {
template_forums_handle(pi,w) template_forums_handle(pi,w)
} else { } else {
@ -315,7 +297,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
topic.ContentLines = strings.Count(content,"\n") topic.ContentLines = strings.Count(content,"\n")
if topic.Is_Closed { if topic.Is_Closed {
topic.Status = "closed" topic.Status = "shut"
// We don't want users posting in locked topics... // We don't want users posting in locked topics...
if !user.Is_Mod { if !user.Is_Mod {
@ -407,9 +389,9 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
return return
} }
tpage := TopicPage{topic.Title,"topic",user,noticeList,replyList,topic,0} tpage := TopicPage{topic.Title,user,noticeList,replyList,topic,0}
if template_topic_handle != nil { //if template_topic_alt_handle != nil { if template_topic_handle != nil {
template_topic_handle(tpage,w) //template_topic_alt_handle(tpage,w) template_topic_handle(tpage,w)
} else { } else {
err = templates.ExecuteTemplate(w,"topic.html", tpage) err = templates.ExecuteTemplate(w,"topic.html", tpage)
if err != nil { if err != nil {

View File

@ -1,12 +1,17 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "io" import "io"
import "strconv" import "strconv"
func init() { func init() {
template_forum_handle = template_forum template_forum_handle = template_forum
//o_template_forum_handle = template_forum
ctemplates = append(ctemplates,"forum")
tmpl_ptr_map["forum"] = &template_forum_handle
tmpl_ptr_map["o_forum"] = template_forum
} }
func template_forum(tmpl_forum_vars Page, w io.Writer) { func template_forum(tmpl_forum_vars ForumPage, w io.Writer) {
w.Write([]byte(`<!doctype html> w.Write([]byte(`<!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
@ -68,20 +73,20 @@ w.Write([]byte(`
if len(tmpl_forum_vars.ItemList) != 0 { if len(tmpl_forum_vars.ItemList) != 0 {
for _, item := range tmpl_forum_vars.ItemList { for _, item := range tmpl_forum_vars.ItemList {
w.Write([]byte(`<div class="rowitem passive" style="`)) w.Write([]byte(`<div class="rowitem passive" style="`))
if item.(TopicUser).Avatar != "" { if item.Avatar != "" {
w.Write([]byte(`background-image: url(` + item.(TopicUser).Avatar + `);background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;`)) w.Write([]byte(`background-image: url(` + item.Avatar + `);background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;`))
} }
if item.(TopicUser).Sticky { if item.Sticky {
w.Write([]byte(`background-color: #FFFFCC;`)) w.Write([]byte(`background-color: #FFFFCC;`))
} else { } else {
if item.(TopicUser).Is_Closed { if item.Is_Closed {
w.Write([]byte(`background-color: #eaeaea;`)) w.Write([]byte(`background-color: #eaeaea;`))
} }
} }
w.Write([]byte(`"> w.Write([]byte(`">
<a href="/topic/` + strconv.Itoa(item.(TopicUser).ID) + `">` + item.(TopicUser).Title + `</a> `)) <a href="/topic/` + strconv.Itoa(item.ID) + `">` + item.Title + `</a> `))
if item.(TopicUser).Is_Closed { if item.Is_Closed {
w.Write([]byte(`<span class="username topic_status_e topic_status_closed" style="float: right;">closed</span> w.Write([]byte(`<span class="username topic_status_e topic_status_closed" style="float: right;">shut</span>
`)) `))
} else { } else {
w.Write([]byte(`<span class="username hide_on_micro topic_status_e topic_status_open" style="float: right;">open</span>`)) w.Write([]byte(`<span class="username hide_on_micro topic_status_e topic_status_open" style="float: right;">open</span>`))

View File

@ -1,12 +1,17 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "io" import "io"
import "strconv" import "strconv"
func init() { func init() {
template_forums_handle = template_forums template_forums_handle = template_forums
//o_template_forums_handle = template_forums
ctemplates = append(ctemplates,"forums")
tmpl_ptr_map["forums"] = &template_forums_handle
tmpl_ptr_map["o_forums"] = template_forums
} }
func template_forums(tmpl_forums_vars Page, w io.Writer) { func template_forums(tmpl_forums_vars ForumsPage, w io.Writer) {
w.Write([]byte(`<!doctype html> w.Write([]byte(`<!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
@ -65,8 +70,8 @@ w.Write([]byte(`
if len(tmpl_forums_vars.ItemList) != 0 { if len(tmpl_forums_vars.ItemList) != 0 {
for _, item := range tmpl_forums_vars.ItemList { for _, item := range tmpl_forums_vars.ItemList {
w.Write([]byte(`<div class="rowitem"> w.Write([]byte(`<div class="rowitem">
<a href="/forum/` + strconv.Itoa(item.(Forum).ID) + `" style="font-size: 20px;position:relative;top: -2px;font-weight: normal;text-transform: none;">` + item.(Forum).Name + `</a> <a href="/forum/` + strconv.Itoa(item.ID) + `" style="font-size: 20px;position:relative;top: -2px;font-weight: normal;text-transform: none;">` + item.Name + `</a>
<a href="/topic/` + strconv.Itoa(item.(Forum).LastTopicID) + `" style="font-weight: normal;text-transform: none;float: right;">` + item.(Forum).LastTopic + ` <small style="font-size: 12px;">` + item.(Forum).LastTopicTime + `</small></a> <a href="/topic/` + strconv.Itoa(item.LastTopicID) + `" style="font-weight: normal;text-transform: none;float: right;">` + item.LastTopic + ` <small style="font-size: 12px;">` + item.LastTopicTime + `</small></a>
</div> </div>
`)) `))
} }

View File

@ -1,9 +1,14 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "strconv"
import "io" import "io"
import "strconv"
func init() { func init() {
template_profile_handle = template_profile template_profile_handle = template_profile
//o_template_profile_handle = template_profile
ctemplates = append(ctemplates,"profile")
tmpl_ptr_map["profile"] = &template_profile_handle
tmpl_ptr_map["o_profile"] = template_profile
} }
func template_profile(tmpl_profile_vars ProfilePage, w io.Writer) { func template_profile(tmpl_profile_vars ProfilePage, w io.Writer) {

View File

@ -1,10 +1,15 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "io" import "io"
import "strconv" import "strconv"
import "html/template" import "html/template"
func init() { func init() {
template_topic_handle = template_topic template_topic_handle = template_topic
//o_template_topic_handle = template_topic
ctemplates = append(ctemplates,"topic")
tmpl_ptr_map["topic"] = &template_topic_handle
tmpl_ptr_map["o_topic"] = template_topic
} }
func template_topic(tmpl_topic_vars TopicPage, w io.Writer) { func template_topic(tmpl_topic_vars TopicPage, w io.Writer) {
@ -91,7 +96,7 @@ w.Write([]byte(`
<input class='show_on_edit topic_name_input' name="topic_name" value='` + tmpl_topic_vars.Topic.Title + `' type="text" /> <input class='show_on_edit topic_name_input' name="topic_name" value='` + tmpl_topic_vars.Topic.Title + `' type="text" />
<select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'> <select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
<option>open</option> <option>open</option>
<option>closed</option> <option>shut</option>
</select> </select>
<button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button> <button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button>
`)) `))

View File

@ -1,10 +1,15 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "strconv"
import "html/template" import "html/template"
import "io" import "io"
import "strconv"
func init() { func init() {
template_topic_alt_handle = template_topic_alt template_topic_alt_handle = template_topic_alt
//o_template_topic_alt_handle = template_topic_alt
ctemplates = append(ctemplates,"topic_alt")
tmpl_ptr_map["topic_alt"] = &template_topic_alt_handle
tmpl_ptr_map["o_topic_alt"] = template_topic_alt
} }
func template_topic_alt(tmpl_topic_alt_vars TopicPage, w io.Writer) { func template_topic_alt(tmpl_topic_alt_vars TopicPage, w io.Writer) {
@ -63,15 +68,17 @@ w.Write([]byte(`<div class="alert">` + item + `</div>`))
w.Write([]byte(` w.Write([]byte(`
<div class="rowblock"> <div class="rowblock">
<form action='/topic/edit/submit/` + strconv.Itoa(tmpl_topic_alt_vars.Topic.ID) + `' method="post"> <form action='/topic/edit/submit/` + strconv.Itoa(tmpl_topic_alt_vars.Topic.ID) + `' method="post">
<div class="rowitem"`)) <div class="rowitem" style="`))
if tmpl_topic_alt_vars.Topic.Sticky { if tmpl_topic_alt_vars.Topic.Sticky {
w.Write([]byte(` style="background-color: #FFFFEA;"`)) w.Write([]byte(`background-color: #FFFFEA;background: linear-gradient(to bottom, hsl(60, 70%, 96%), hsl(60, 70%, 89%)), url('/static/fabric-base-simple-alpha.png');`))
} else { } else {
if tmpl_topic_alt_vars.Topic.Is_Closed { if tmpl_topic_alt_vars.Topic.Is_Closed {
w.Write([]byte(` style="background-color: #eaeaea;"`)) w.Write([]byte(`background-color: #eaeaea;background: linear-gradient(to bottom, #eaeaea, hsl(0,0%,79%));`))
} else {
w.Write([]byte(`background: linear-gradient(to bottom, white, hsl(0, 0%, 93%));`))
} }
} }
w.Write([]byte(`> w.Write([]byte(`">
<a class='topic_name hide_on_edit'>` + tmpl_topic_alt_vars.Topic.Title + `</a> <a class='topic_name hide_on_edit'>` + tmpl_topic_alt_vars.Topic.Title + `</a>
<span class='username hide_on_micro topic_status_e topic_status_` + tmpl_topic_alt_vars.Topic.Status + ` hide_on_edit' style="font-weight:normal;float: right;">` + tmpl_topic_alt_vars.Topic.Status + `</span> <span class='username hide_on_micro topic_status_e topic_status_` + tmpl_topic_alt_vars.Topic.Status + ` hide_on_edit' style="font-weight:normal;float: right;">` + tmpl_topic_alt_vars.Topic.Status + `</span>
<span class="username hide_on_micro" style="border-right: 0;font-weight: normal;float: right;">Status</span> <span class="username hide_on_micro" style="border-right: 0;font-weight: normal;float: right;">Status</span>
@ -91,7 +98,7 @@ w.Write([]byte(`
<input class='show_on_edit topic_name_input' name="topic_name" value='` + tmpl_topic_alt_vars.Topic.Title + `' type="text" /> <input class='show_on_edit topic_name_input' name="topic_name" value='` + tmpl_topic_alt_vars.Topic.Title + `' type="text" />
<select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'> <select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
<option>open</option> <option>open</option>
<option>closed</option> <option>shut</option>
</select> </select>
<button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button> <button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button>
`)) `))
@ -104,7 +111,7 @@ w.Write([]byte(`
<style type="text/css">.rowitem:last-child .content_container { margin-bottom: 5px !important; }</style> <style type="text/css">.rowitem:last-child .content_container { margin-bottom: 5px !important; }</style>
<div class="rowblock post_container" style="border-top: none;"> <div class="rowblock post_container" style="border-top: none;">
<div class="rowitem passive deletable_block editable_parent post_item" style="background-color: #eaeaea;padding-top: 4px;padding-left: 5px;clear: both;border-bottom: none;padding-right: 4px;padding-bottom: 2px;"> <div class="rowitem passive deletable_block editable_parent post_item" style="background-color: #eaeaea;padding-top: 4px;padding-left: 5px;clear: both;border-bottom: none;padding-right: 4px;padding-bottom: 2px;">
<div class="userinfo" style="background: white;width: 132px;padding: 2px;margin-top: 2px;float: left;box-shadow:0 1px 2px rgba(0,0,0,.1);"> <div class="userinfo" style="background: white;width: 132px;padding: 2px;margin-top: 2px;float: left;position: sticky;top: 4px;box-shadow:0 1px 2px rgba(0,0,0,.1);">
<div class="avatar_item" style="background-image: url(` + tmpl_topic_alt_vars.Topic.Avatar + `), url(/static/white-dot.jpg);background-position: 0px -10px;background-repeat: no-repeat, repeat-y;background-size: 128px;width: 128px;height: 100%;min-height: 128px;border-style: solid;border-color: #eaeaea;border-width: 1px;">&nbsp;</div> <div class="avatar_item" style="background-image: url(` + tmpl_topic_alt_vars.Topic.Avatar + `), url(/static/white-dot.jpg);background-position: 0px -10px;background-repeat: no-repeat, repeat-y;background-size: 128px;width: 128px;height: 100%;min-height: 128px;border-style: solid;border-color: #eaeaea;border-width: 1px;">&nbsp;</div>
<div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">` + tmpl_topic_alt_vars.Topic.CreatedByName + `</div> <div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">` + tmpl_topic_alt_vars.Topic.CreatedByName + `</div>
</div> </div>
@ -118,7 +125,7 @@ if len(tmpl_topic_alt_vars.ItemList) != 0 {
for _, item := range tmpl_topic_alt_vars.ItemList { for _, item := range tmpl_topic_alt_vars.ItemList {
w.Write([]byte(` w.Write([]byte(`
<div class="rowitem passive deletable_block editable_parent post_item" style="background-color: #eaeaea;padding-top: 4px;padding-left: 5px;clear: both;border-bottom: none;padding-right: 4px;padding-bottom: 2px;"> <div class="rowitem passive deletable_block editable_parent post_item" style="background-color: #eaeaea;padding-top: 4px;padding-left: 5px;clear: both;border-bottom: none;padding-right: 4px;padding-bottom: 2px;">
<div class="userinfo" style="background: white;width: 132px;padding: 2px;margin-top: 2px;float: left;box-shadow:0 1px 2px rgba(0,0,0,.1);"> <div class="userinfo" style="background: white;width: 132px;padding: 2px;margin-top: 2px;float: left;position: sticky;top: 4px;box-shadow:0 1px 2px rgba(0,0,0,.1);">
<div class="avatar_item" style="background-image: url(` + item.Avatar + `), url(/static/white-dot.jpg);background-position: 0px -10px;background-repeat: no-repeat, repeat-y;background-size: 128px;width: 128px;height: 100%;min-height: 128px;border-style: solid;border-color: #eaeaea;border-width: 1px;">&nbsp;</div> <div class="avatar_item" style="background-image: url(` + item.Avatar + `), url(/static/white-dot.jpg);background-position: 0px -10px;background-repeat: no-repeat, repeat-y;background-size: 128px;width: 128px;height: 100%;min-height: 128px;border-style: solid;border-color: #eaeaea;border-width: 1px;">&nbsp;</div>
<div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">` + item.CreatedByName + `</div> <div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">` + item.CreatedByName + `</div>
</div> </div>
@ -146,7 +153,7 @@ w.Write([]byte(`</div>
`)) `))
if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply { if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply {
w.Write([]byte(` w.Write([]byte(`
<div class="rowblock"> <div class="rowblock" style="border-top: none;">
<form action="/reply/create/" method="post"> <form action="/reply/create/" method="post">
<input name="tid" value='` + strconv.Itoa(tmpl_topic_alt_vars.Topic.ID) + `' type="hidden" /> <input name="tid" value='` + strconv.Itoa(tmpl_topic_alt_vars.Topic.ID) + `' type="hidden" />
<div class="formrow"> <div class="formrow">

View File

@ -1,12 +1,17 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "io" import "io"
import "strconv" import "strconv"
func init() { func init() {
template_topics_handle = template_topics template_topics_handle = template_topics
//o_template_topics_handle = template_topics
ctemplates = append(ctemplates,"topics")
tmpl_ptr_map["topics"] = &template_topics_handle
tmpl_ptr_map["o_topics"] = template_topics
} }
func template_topics(tmpl_topics_vars Page, w io.Writer) { func template_topics(tmpl_topics_vars TopicsPage, w io.Writer) {
w.Write([]byte(`<!doctype html> w.Write([]byte(`<!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
@ -68,20 +73,20 @@ w.Write([]byte(`
if len(tmpl_topics_vars.ItemList) != 0 { if len(tmpl_topics_vars.ItemList) != 0 {
for _, item := range tmpl_topics_vars.ItemList { for _, item := range tmpl_topics_vars.ItemList {
w.Write([]byte(`<div class="rowitem passive" style="`)) w.Write([]byte(`<div class="rowitem passive" style="`))
if item.(TopicUser).Avatar != "" { if item.Avatar != "" {
w.Write([]byte(`background-image: url(` + item.(TopicUser).Avatar + `);background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;`)) w.Write([]byte(`background-image: url(` + item.Avatar + `);background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;`))
} }
if item.(TopicUser).Sticky { if item.Sticky {
w.Write([]byte(`background-color: #FFFFCC;`)) w.Write([]byte(`background-color: #FFFFCC;`))
} else { } else {
if item.(TopicUser).Is_Closed { if item.Is_Closed {
w.Write([]byte(`background-color: #eaeaea;`)) w.Write([]byte(`background-color: #eaeaea;`))
} }
} }
w.Write([]byte(`"> w.Write([]byte(`">
<a href="/topic/` + strconv.Itoa(item.(TopicUser).ID) + `">` + item.(TopicUser).Title + `</a> `)) <a href="/topic/` + strconv.Itoa(item.ID) + `">` + item.Title + `</a> `))
if item.(TopicUser).Is_Closed { if item.Is_Closed {
w.Write([]byte(`<span class="username topic_status_e topic_status_closed" style="float: right;">closed</span> w.Write([]byte(`<span class="username topic_status_e topic_status_closed" style="float: right;">shut</span>
`)) `))
} else { } else {
w.Write([]byte(`<span class="username hide_on_micro topic_status_e topic_status_open" style="float: right;">open</span>`)) w.Write([]byte(`<span class="username hide_on_micro topic_status_e topic_status_open" style="float: right;">open</span>`))

View File

@ -8,6 +8,9 @@ import "path/filepath"
import "io/ioutil" import "io/ioutil"
import "text/template/parse" import "text/template/parse"
var ctemplates []string
var tmpl_ptr_map map[string]interface{} = make(map[string]interface{})
type VarItem struct type VarItem struct
{ {
Name string Name string
@ -76,7 +79,6 @@ func (c *CTemplateSet) compile_template(name string, dir string, expects string,
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if debug { if debug {
fmt.Println(name) fmt.Println(name)
} }
@ -90,7 +92,6 @@ func (c *CTemplateSet) compile_template(name string, dir string, expects string,
if debug { if debug {
fmt.Println(c.tlist) fmt.Println(c.tlist)
} }
c.localVars = make(map[string]map[string]VarItemReflect) c.localVars = make(map[string]map[string]VarItemReflect)
c.localVars[fname] = make(map[string]VarItemReflect) c.localVars[fname] = make(map[string]VarItemReflect)
c.localVars[fname]["."] = VarItemReflect{".",varholder,holdreflect} c.localVars[fname]["."] = VarItemReflect{".",varholder,holdreflect}
@ -126,11 +127,14 @@ func (c *CTemplateSet) compile_template(name string, dir string, expects string,
varString += "var " + varItem.Name + " " + varItem.Type + " = " + varItem.Destination + "\n" varString += "var " + varItem.Name + " " + varItem.Type + " = " + varItem.Destination + "\n"
} }
out = "package main\n" + importList + c.pVarList + "\nfunc init() {\ntemplate_" + fname +"_handle = template_" + fname + "\n}\n\nfunc template_" + fname + "(tmpl_" + fname + "_vars " + expects + ", w io.Writer) {\n" + varString + out + "}\n" fout := "/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n"
fout += "package main\n" + importList + c.pVarList + "\n"
fout += "func init() {\n\ttemplate_" + fname +"_handle = template_" + fname + "\n\t//o_template_" + fname +"_handle = template_" + fname + "\n\tctemplates = append(ctemplates,\"" + fname + "\")\n\ttmpl_ptr_map[\"" + fname + "\"] = &template_" + fname + "_handle\n\ttmpl_ptr_map[\"o_" + fname + "\"] = template_" + fname + "\n}\n\n"
fout += "func template_" + fname + "(tmpl_" + fname + "_vars " + expects + ", w io.Writer) {\n" + varString + out + "}\n"
out = strings.Replace(out,`)) fout = strings.Replace(fout,`))
w.Write([]byte(`," + ",-1) w.Write([]byte(`," + ",-1)
out = strings.Replace(out,"` + `","",-1) fout = strings.Replace(fout,"` + `","",-1)
for index, count := range c.stats { for index, count := range c.stats {
fmt.Println(index + ": " + strconv.Itoa(count)) fmt.Println(index + ": " + strconv.Itoa(count))
@ -139,9 +143,9 @@ w.Write([]byte(`," + ",-1)
if debug { if debug {
fmt.Println("Output!") fmt.Println("Output!")
fmt.Println(out) fmt.Println(fout)
} }
return out return fout
} }
func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Value, template_name string, node interface{}) (out string) { func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Value, template_name string, node interface{}) (out string) {
@ -380,7 +384,6 @@ func (c *CTemplateSet) compile_varswitch(varholder string, holdreflect reflect.V
fmt.Println(n.String()) fmt.Println(n.String())
fmt.Println(n.Ident) fmt.Println(n.Ident)
} }
out, _ = c.compile_if_varsub(n.String(), varholder, template_name, holdreflect) out, _ = c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
return out return out
case *parse.NilNode: case *parse.NilNode:

View File

@ -4,7 +4,7 @@
</div> </div>
<div class="rowblock"> <div class="rowblock">
{{range .ItemList}}<div class="rowitem passive" style="{{ if .Avatar }}background-image: url({{ .Avatar }});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}{{ if .Sticky }}background-color: #FFFFCC;{{else if .Is_Closed}}background-color: #eaeaea;{{end}}"> {{range .ItemList}}<div class="rowitem passive" style="{{ if .Avatar }}background-image: url({{ .Avatar }});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}{{ if .Sticky }}background-color: #FFFFCC;{{else if .Is_Closed}}background-color: #eaeaea;{{end}}">
<a href="/topic/{{.ID}}">{{.Title}}</a> {{if .Is_Closed}}<span class="username topic_status_e topic_status_closed" style="float: right;">closed</span> <a href="/topic/{{.ID}}">{{.Title}}</a> {{if .Is_Closed}}<span class="username topic_status_e topic_status_closed" style="float: right;">shut</span>
{{else}}<span class="username hide_on_micro topic_status_e topic_status_open" style="float: right;">open</span>{{end}} {{else}}<span class="username hide_on_micro topic_status_e topic_status_open" style="float: right;">open</span>{{end}}
<span class="username hide_on_micro" style="border-right: 0;float: right;">Status</span> <span class="username hide_on_micro" style="border-right: 0;float: right;">Status</span>
</div> </div>

View File

@ -4,9 +4,7 @@
<div class="rowitem passive"><a href="/panel/groups/">Groups</a></div> <div class="rowitem passive"><a href="/panel/groups/">Groups</a></div>
{{if .CurrentUser.Perms.ManageForums}}<div class="rowitem passive"><a href="/panel/forums/">Forums</a></div>{{end}} {{if .CurrentUser.Perms.ManageForums}}<div class="rowitem passive"><a href="/panel/forums/">Forums</a></div>{{end}}
{{if .CurrentUser.Perms.EditSettings}}<div class="rowitem passive"><a href="/panel/settings/">Settings</a></div>{{end}} {{if .CurrentUser.Perms.EditSettings}}<div class="rowitem passive"><a href="/panel/settings/">Settings</a></div>{{end}}
{{if .CurrentUser.Perms.ManageThemes}}<div class="rowitem passive"><a href="/panel/themes/">Themes</a></div>{{end}}
{{if .CurrentUser.Perms.ManagePlugins}}<div class="rowitem passive"><a href="/panel/plugins/">Plugins</a></div>{{end}} {{if .CurrentUser.Perms.ManagePlugins}}<div class="rowitem passive"><a href="/panel/plugins/">Plugins</a></div>{{end}}
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a href="/forum/-1">Reported Content</a></div> <div class="rowitem passive"><a href="/forum/-1">Reported Content</a></div>
</div> </div>

View File

@ -0,0 +1,20 @@
{{template "header.html" . }}
{{template "panel-menu.html" . }}
<style type="text/css">.rowitem::after {content:"";display:block;clear:both;}</style>
<div class="colblock_right">
<div class="rowitem"><a>Themes</a></div>
</div>
<div class="colblock_right">
{{range .ItemList}}
<div class="rowitem editable_parent" style="font-weight: normal;text-transform: none;">
<span style="float: left;">
<a href="/panel/themes/{{.Name}}" class="editable_block" style="font-size: 20px;">{{.FriendlyName}}</a><br />
<small style="margin-left: 2px;">Author: {{.Creator}}</small>
</span>
<span style="float: right;">
{{if .Active}}<span>Default</span>{{else}}<a href="/panel/themes/default/{{.Name}}?session={{$.CurrentUser.Session}}" class="username">Make Default</a>{{end}}
</span>
</div>
{{end}}
</div>
{{template "footer.html" . }}

View File

@ -13,7 +13,7 @@
<input class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" /> <input class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" />
<select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'> <select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
<option>open</option> <option>open</option>
<option>closed</option> <option>shut</option>
</select> </select>
<button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button> <button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button>
{{end}} {{end}}

View File

@ -1,7 +1,7 @@
{{template "header.html" . }} {{template "header.html" . }}
<div class="rowblock"> <div class="rowblock">
<form action='/topic/edit/submit/{{.Topic.ID}}' method="post"> <form action='/topic/edit/submit/{{.Topic.ID}}' method="post">
<div class="rowitem"{{ if .Topic.Sticky }} style="background-color: #FFFFEA;"{{else if .Topic.Is_Closed}} style="background-color: #eaeaea;"{{end}}> <div class="rowitem" style="{{ if .Topic.Sticky }}background-color: #FFFFEA;background: linear-gradient(to bottom, hsl(60, 70%, 96%), hsl(60, 70%, 89%)), url('/static/fabric-base-simple-alpha.png');{{else if .Topic.Is_Closed}}background-color: #eaeaea;background: linear-gradient(to bottom, #eaeaea, hsl(0,0%,79%));{{else}}background: linear-gradient(to bottom, white, hsl(0, 0%, 93%));{{end}}">
<a class='topic_name hide_on_edit'>{{.Topic.Title}}</a> <a class='topic_name hide_on_edit'>{{.Topic.Title}}</a>
<span class='username hide_on_micro topic_status_e topic_status_{{.Topic.Status}} hide_on_edit' style="font-weight:normal;float: right;">{{.Topic.Status}}</span> <span class='username hide_on_micro topic_status_e topic_status_{{.Topic.Status}} hide_on_edit' style="font-weight:normal;float: right;">{{.Topic.Status}}</span>
<span class="username hide_on_micro" style="border-right: 0;font-weight: normal;float: right;">Status</span> <span class="username hide_on_micro" style="border-right: 0;font-weight: normal;float: right;">Status</span>
@ -13,7 +13,7 @@
<input class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" /> <input class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" />
<select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'> <select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
<option>open</option> <option>open</option>
<option>closed</option> <option>shut</option>
</select> </select>
<button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button> <button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button>
{{end}} {{end}}
@ -24,7 +24,7 @@
<style type="text/css">.rowitem:last-child .content_container { margin-bottom: 5px !important; }</style> <style type="text/css">.rowitem:last-child .content_container { margin-bottom: 5px !important; }</style>
<div class="rowblock post_container" style="border-top: none;"> <div class="rowblock post_container" style="border-top: none;">
<div class="rowitem passive deletable_block editable_parent post_item" style="background-color: #eaeaea;padding-top: 4px;padding-left: 5px;clear: both;border-bottom: none;padding-right: 4px;padding-bottom: 2px;"> <div class="rowitem passive deletable_block editable_parent post_item" style="background-color: #eaeaea;padding-top: 4px;padding-left: 5px;clear: both;border-bottom: none;padding-right: 4px;padding-bottom: 2px;">
<div class="userinfo" style="background: white;width: 132px;padding: 2px;margin-top: 2px;float: left;box-shadow:0 1px 2px rgba(0,0,0,.1);"> <div class="userinfo" style="background: white;width: 132px;padding: 2px;margin-top: 2px;float: left;position: sticky;top: 4px;box-shadow:0 1px 2px rgba(0,0,0,.1);">
<div class="avatar_item" style="background-image: url({{.Topic.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;background-repeat: no-repeat, repeat-y;background-size: 128px;width: 128px;height: 100%;min-height: 128px;border-style: solid;border-color: #eaeaea;border-width: 1px;">&nbsp;</div> <div class="avatar_item" style="background-image: url({{.Topic.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;background-repeat: no-repeat, repeat-y;background-size: 128px;width: 128px;height: 100%;min-height: 128px;border-style: solid;border-color: #eaeaea;border-width: 1px;">&nbsp;</div>
<div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">{{.Topic.CreatedByName}}</div> <div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">{{.Topic.CreatedByName}}</div>
</div> </div>
@ -35,7 +35,7 @@
</div> </div>
{{range .ItemList}} {{range .ItemList}}
<div class="rowitem passive deletable_block editable_parent post_item" style="background-color: #eaeaea;padding-top: 4px;padding-left: 5px;clear: both;border-bottom: none;padding-right: 4px;padding-bottom: 2px;"> <div class="rowitem passive deletable_block editable_parent post_item" style="background-color: #eaeaea;padding-top: 4px;padding-left: 5px;clear: both;border-bottom: none;padding-right: 4px;padding-bottom: 2px;">
<div class="userinfo" style="background: white;width: 132px;padding: 2px;margin-top: 2px;float: left;box-shadow:0 1px 2px rgba(0,0,0,.1);"> <div class="userinfo" style="background: white;width: 132px;padding: 2px;margin-top: 2px;float: left;position: sticky;top: 4px;box-shadow:0 1px 2px rgba(0,0,0,.1);">
<div class="avatar_item" style="background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;background-repeat: no-repeat, repeat-y;background-size: 128px;width: 128px;height: 100%;min-height: 128px;border-style: solid;border-color: #eaeaea;border-width: 1px;">&nbsp;</div> <div class="avatar_item" style="background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;background-repeat: no-repeat, repeat-y;background-size: 128px;width: 128px;height: 100%;min-height: 128px;border-style: solid;border-color: #eaeaea;border-width: 1px;">&nbsp;</div>
<div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">{{.CreatedByName}}</div> <div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">{{.CreatedByName}}</div>
</div> </div>
@ -50,7 +50,7 @@
</div> </div>
{{end}}</div> {{end}}</div>
{{if .CurrentUser.Perms.CreateReply}} {{if .CurrentUser.Perms.CreateReply}}
<div class="rowblock"> <div class="rowblock" style="border-top: none;">
<form action="/reply/create/" method="post"> <form action="/reply/create/" method="post">
<input name="tid" value='{{.Topic.ID}}' type="hidden" /> <input name="tid" value='{{.Topic.ID}}' type="hidden" />
<div class="formrow"> <div class="formrow">

View File

@ -4,7 +4,7 @@
</div> </div>
<div class="rowblock"> <div class="rowblock">
{{range .ItemList}}<div class="rowitem passive" style="{{if .Avatar}}background-image: url({{.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}{{if .Sticky}}background-color: #FFFFCC;{{else if .Is_Closed}}background-color: #eaeaea;{{end}}"> {{range .ItemList}}<div class="rowitem passive" style="{{if .Avatar}}background-image: url({{.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}{{if .Sticky}}background-color: #FFFFCC;{{else if .Is_Closed}}background-color: #eaeaea;{{end}}">
<a href="/topic/{{.ID}}">{{.Title}}</a> {{if .Is_Closed}}<span class="username topic_status_e topic_status_closed" style="float: right;">closed</span> <a href="/topic/{{.ID}}">{{.Title}}</a> {{if .Is_Closed}}<span class="username topic_status_e topic_status_closed" style="float: right;">shut</span>
{{else}}<span class="username hide_on_micro topic_status_e topic_status_open" style="float: right;">open</span>{{end}} {{else}}<span class="username hide_on_micro topic_status_e topic_status_open" style="float: right;">open</span>{{end}}
<span class="username hide_on_micro" style="border-right: 0;float: right;">Status</span> <span class="username hide_on_micro" style="border-right: 0;float: right;">Status</span>
</div> </div>

319
themes.go Normal file
View File

@ -0,0 +1,319 @@
/* Copyright Azareal 2016 - 2017 */
package main
import "fmt"
import "log"
import "io"
import "os"
import "strings"
import "mime"
import "io/ioutil"
import "path/filepath"
import "encoding/json"
import "net/http"
var defaultTheme string
var themes map[string]Theme = make(map[string]Theme)
//var overriden_templates map[string]interface{} = make(map[string]interface{})
var overriden_templates map[string]bool = make(map[string]bool)
type Theme struct
{
Name string
FriendlyName string
Version string
Creator string
Settings map[string]ThemeSetting
Templates []TemplateMapping
// This variable should only be set and unset by the system, not the theme meta file
Active bool
}
type ThemeSetting struct
{
FriendlyName string
Options []string
}
type TemplateMapping struct
{
Name string
Source string
//When string
}
func init_themes() {
themeFiles, err := ioutil.ReadDir("./themes")
if err != nil {
log.Fatal(err)
}
for _, themeFile := range themeFiles {
if !themeFile.IsDir() {
continue
}
themeName := themeFile.Name()
log.Print("Adding theme '" + themeName + "'")
themeFile, err := ioutil.ReadFile("./themes/" + themeName + "/theme.json")
if err != nil {
log.Fatal(err)
}
var theme Theme
json.Unmarshal(themeFile, &theme)
theme.Active = false // Set this to false, just in case someone explicitly overrode this value in the JSON file
themes[theme.Name] = theme
}
}
func add_theme_static_files(themeName string) {
err := filepath.Walk("./themes/" + themeName + "/public", func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
if f.IsDir() {
return nil
}
path = strings.Replace(path,"\\","/",-1)
log.Print("Attempting to add static file '" + path + "' for default theme '" + themeName + "'")
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
path = strings.TrimPrefix(path,"themes/" + themeName + "/public")
log.Print("Added the '" + path + "' static file for default theme " + themeName + ".")
static_files["/static" + path] = SFile{data,0,int64(len(data)),mime.TypeByExtension(filepath.Ext("/themes/" + themeName + "/public" + path)),f,f.ModTime().UTC().Format(http.TimeFormat)}
return nil
})
if err != nil {
panic(err)
}
}
func map_theme_templates(theme Theme) {
if theme.Templates != nil {
for _, themeTmpl := range theme.Templates {
if themeTmpl.Name == "" {
log.Fatal("Invalid destination template name")
}
if themeTmpl.Source == "" {
log.Fatal("Invalid source template name")
}
// go generate is one possibility, but it would simply add another step of compilation
dest_tmpl_ptr, ok := tmpl_ptr_map[themeTmpl.Name]
if !ok {
log.Fatal("The destination template doesn't exist!")
}
source_tmpl_ptr, ok := tmpl_ptr_map[themeTmpl.Source]
if !ok {
log.Fatal("The source template doesn't exist!")
}
switch d_tmpl_ptr := dest_tmpl_ptr.(type) {
case *func(TopicPage,io.Writer):
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
case *func(TopicPage,io.Writer):
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
overriden_templates[themeTmpl.Name] = true
log.Print("Topic Handle")
fmt.Println(template_topic_handle)
log.Print("Before")
fmt.Println(d_tmpl_ptr)
fmt.Println(*d_tmpl_ptr)
log.Print("Source")
fmt.Println(s_tmpl_ptr)
fmt.Println(*s_tmpl_ptr)
*d_tmpl_ptr = *s_tmpl_ptr
log.Print("After")
fmt.Println(d_tmpl_ptr)
fmt.Println(*d_tmpl_ptr)
log.Print("Source")
fmt.Println(s_tmpl_ptr)
fmt.Println(*s_tmpl_ptr)
default:
log.Fatal("The source and destination templates are incompatible")
}
case *func(TopicsPage,io.Writer):
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
case *func(TopicsPage,io.Writer):
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
overriden_templates[themeTmpl.Name] = true
*d_tmpl_ptr = *s_tmpl_ptr
default:
log.Fatal("The source and destination templates are incompatible")
}
case *func(ForumPage,io.Writer):
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
case *func(ForumPage,io.Writer):
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
overriden_templates[themeTmpl.Name] = true
*d_tmpl_ptr = *s_tmpl_ptr
default:
log.Fatal("The source and destination templates are incompatible")
}
case *func(ForumsPage,io.Writer):
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
case *func(ForumsPage,io.Writer):
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
overriden_templates[themeTmpl.Name] = true
*d_tmpl_ptr = *s_tmpl_ptr
default:
log.Fatal("The source and destination templates are incompatible")
}
case *func(ProfilePage,io.Writer):
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
case *func(ProfilePage,io.Writer):
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
overriden_templates[themeTmpl.Name] = true
*d_tmpl_ptr = *s_tmpl_ptr
default:
log.Fatal("The source and destination templates are incompatible")
}
case *func(Page,io.Writer):
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
case *func(Page,io.Writer):
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
overriden_templates[themeTmpl.Name] = true
*d_tmpl_ptr = *s_tmpl_ptr
default:
log.Fatal("The source and destination templates are incompatible")
}
default:
log.Fatal("Unknown destination template type!")
}
}
}
}
func reset_template_overrides() {
log.Print("Resetting the template overrides")
for name, _ := range overriden_templates {
log.Print("Resetting '" + name + "' template override")
origin_pointer, ok := tmpl_ptr_map["o_" + name]
if !ok {
//log.Fatal("The origin template doesn't exist!")
log.Print("The origin template doesn't exist!")
return
}
dest_tmpl_ptr, ok := tmpl_ptr_map[name]
if !ok {
//log.Fatal("The destination template doesn't exist!")
log.Print("The destination template doesn't exist!")
return
}
switch o_ptr := origin_pointer.(type) {
case func(TopicPage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(TopicPage,io.Writer):
log.Print("Topic Handle")
fmt.Println(template_topic_handle)
log.Print("Before")
fmt.Println(d_ptr)
fmt.Println(*d_ptr)
log.Print("Origin")
fmt.Println(o_ptr)
*d_ptr = o_ptr
log.Print("After")
fmt.Println(d_ptr)
fmt.Println(*d_ptr)
log.Print("Origin")
fmt.Println(o_ptr)
default:
log.Fatal("The origin and destination templates are incompatible")
}
case *func(TopicsPage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(TopicsPage,io.Writer):
*d_ptr = o_ptr
default:
log.Fatal("The origin and destination templates are incompatible")
}
case *func(ForumPage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(ForumPage,io.Writer):
*d_ptr = o_ptr
default:
log.Fatal("The origin and destination templates are incompatible")
}
case *func(ForumsPage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(ForumsPage,io.Writer):
*d_ptr = o_ptr
default:
log.Fatal("The origin and destination templates are incompatible")
}
case *func(ProfilePage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(ProfilePage,io.Writer):
*d_ptr = o_ptr
default:
log.Fatal("The origin and destination templates are incompatible")
}
default:
log.Fatal("Unknown destination template type!")
}
log.Print("The template override was reset")
}
overriden_templates = make(map[string]bool)
log.Print("All of the template overrides have been reset")
/*for name, origin_pointer := range overriden_templates {
dest_tmpl_ptr, ok := tmpl_ptr_map[name]
if !ok {
log.Fatal("The destination template doesn't exist!")
}
switch o_ptr := origin_pointer.(type) {
case *func(TopicPage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(TopicPage,io.Writer):
*d_ptr = *o_ptr
default:
log.Fatal("The origin and destination templates are incompatible")
}
case *func(TopicsPage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(TopicsPage,io.Writer):
*d_ptr = *o_ptr
default:
log.Fatal("The origin and destination templates are incompatible")
}
case *func(ForumPage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(ForumPage,io.Writer):
*d_ptr = *o_ptr
default:
log.Fatal("The origin and destination templates are incompatible")
}
case *func(ForumsPage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(ForumsPage,io.Writer):
*d_ptr = *o_ptr
default:
log.Fatal("The origin and destination templates are incompatible")
}
case *func(ProfilePage,io.Writer):
switch d_ptr := dest_tmpl_ptr.(type) {
case *func(ProfilePage,io.Writer):
*d_ptr = *o_ptr
default:
log.Fatal("The origin and destination templates are incompatible")
}
default:
log.Fatal("Unknown destination template type!")
}
delete(overriden_templates, name)
}*/
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

12
themes/cosmo/theme.json Normal file
View File

@ -0,0 +1,12 @@
{
"Name": "cosmo",
"FriendlyName": "AtomBB Cosmo",
"Version": "Coming Soon",
"Creator": "Azareal",
"Templates": [
{
"Name": "topic",
"Source": "topic_alt"
}
]
}

View File

@ -0,0 +1,12 @@
{
"Name": "tempra-conflux",
"FriendlyName": "Tempra Conflux",
"Version": "0.0.1",
"Creator": "Azareal",
"Templates": [
{
"Name": "topic",
"Source": "topic_alt"
}
]
}

View File

@ -0,0 +1,409 @@
* {
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
body
{
font-family: arial;
}
@font-face {
font-family: 'EmojiFont';
src: url('https://github.com/Ranks/emojione/raw/master/assets/fonts/emojione-svg.woff2') format('woff2'),
url('https://github.com/Ranks/emojione/raw/master/assets/fonts/emojione-svg.woff') format('woff'), local("arial");
}
@supports (-ms-ime-align:auto) {
.user_content
{
font-family: EmojiFont, arial;
}
}
@-moz-document url-prefix() {
.user_content
{
font-family: EmojiFont, arial;
}
}
/*.move_left{float: left;position: relative;left: 50%;}
.move_right{float: left;position: relative;left: -50%;}*/
ul
{
padding-left: 0px;
padding-right: 0px;
height: 28px;
list-style-type: none;
border: 1px solid #ccc;
}
li
{
height: 26px;
padding-left: 10px;
padding-top: 5px;
padding-bottom: 5px;
font-weight: bold;
text-transform: uppercase;
}
li:hover { background: rgb(250,250,250); }
li a
{
text-decoration: none;
color: #515151;
}
/*li a:hover { color: #7a7a7a; }*/
.menu_left
{
float: left;
border-right: 1px solid #ccc;
padding-right: 10px;
}
.menu_right
{
float: right;
border-left: 1px solid #ccc;
padding-right: 10px;
}
.container
{
width: 90%;
padding: 0px;
margin-left: auto;
margin-right: auto;
}
.rowblock
{
border: 1px solid #ccc;
width: 100%;
padding: 0px;
padding-top: 0px;
}
.rowblock:empty
{
display: none;
}
.colblock_left
{
border: 1px solid #ccc;
padding: 0px;
padding-top: 0px;
width: 30%;
float: left;
margin-right: 8px;
}
.colblock_right
{
border: 1px solid #ccc;
padding: 0px;
padding-top: 0px;
width: 65%;
overflow: hidden;
word-wrap: break-word;
}
.colblock_left:empty
{
display: none;
}
.colblock_right:empty
{
display: none;
}
.rowitem
{
width: 100%;
padding-left: 8px;
padding-right: 8px;
padding-top: 17px;
padding-bottom: 12px;
font-weight: bold;
text-transform: uppercase;
}
.rowitem.passive
{
font-weight: normal;
text-transform: none;
}
.rowitem:not(:last-child)
{
border-bottom: 1px dotted #ccc;
}
.rowitem a
{
text-decoration: none;
color: black;
}
.rowitem a:hover
{
color: silver;
}
.col_left
{
width: 30%;
float: left;
}
.col_right
{
width: 69%;
overflow: hidden;
}
.colitem
{
padding-left: 8px;
padding-right: 8px;
padding-top: 17px;
padding-bottom: 12px;
font-weight: bold;
text-transform: uppercase;
}
.colitem.passive
{
font-weight: normal;
text-transform: none;
}
.colitem a
{
text-decoration: none;
color: black;
}
.colitem a:hover
{
color: silver;
}
.formrow
{
/*height: 40px;*/
width: 100%;
}
/*Clearfix*/
.formrow:before,
.formrow:after {
content: " ";
display: table;
}
.formrow:after {
clear: both;
}
.formrow:not(:last-child)
{
border-bottom: 1px dotted #ccc;
}
.formitem
{
float: left;
padding-left: 8px;
padding-right: 8px;
padding-top: 13px;
padding-bottom: 8px;
font-weight: bold;
}
.formitem:first-child
{
font-weight: bold;
}
.formitem:not(:last-child)
{
border-right: 1px dotted #ccc;
}
.formitem.invisible_border
{
border: none;
}
/* Mostly for textareas */
.formitem:only-child
{
width: 97%;
}
.formitem textarea
{
width: 100%;
height: 100px;
}
.formitem:has-child()
{
margin: 0 auto;
float: none;
}
button
{
background: white;
border: 1px solid #8e8e8e;
}
/* Topics */
.topic_status
{
text-transform: none;
margin-left: 8px;
padding-left: 2px;
padding-right: 2px;
padding-top: 2px;
padding-bottom: 2px;
background-color: #E8E8E8; /* 232,232,232. All three RGB colours being the same seems to create a shade of gray */
color: #505050; /* 80,80,80 */
border-radius: 2px;
}
.topic_status:empty
{
display: none;
}
.username
{
text-transform: none;
margin-left: 0px;
padding-left: 4px;
padding-right: 4px;
padding-top: 2px;
padding-bottom: 2px;
color: #505050; /* 80,80,80 */
background-color: #FFFFFF;
border-style: dotted;
border-color: #505050; /* 232,232,232. All three RGB colours being the same seems to create a shade of gray */
border-width: 1px;
font-size: 15px;
}
button.username
{
position: relative;
top: -0.25px;
}
.tag-mini
{
text-transform: none;
margin-left: 0px;
padding-left: 3px;
padding-right: 3px;
padding-top: 1.5px;
padding-bottom: 0px;
color: #505050; /* 80,80,80 */
background-color: #FFFFFF;
border-style: dotted;
border-color: #505050; /* 232,232,232. All three RGB colours being the same seems to create a shade of gray */
border-width: 1px;
font-size: 10px;
}
.show_on_edit
{
display: none;
}
.alert
{
display: block;
padding: 5px;
margin-bottom: 10px;
border: 1px solid #ccc;
}
.alert_success
{
display: block;
padding: 5px;
border: 1px solid A2FC00;
margin-bottom: 10px;
background-color: DAF7A6;
}
.alert_error
{
display: block;
padding: 5px;
border: 1px solid #FF004B;
margin-bottom: 8px;
background-color: #FEB7CC;
}
@media (max-width: 880px) {
li
{
height: 25px;
font-size: 15px;
padding-left: 7px;
}
ul { height: 26px; margin-top: 8px; }
.menu_left { padding-right: 7px; }
.menu_right { padding-right: 7px; }
body { padding-left: 4px; padding-right: 4px; margin: 0px !important; width: 100% !important; height: 100% !important; overflow-x: hidden; }
.container { width: auto; }
}
@media (max-width: 810px) {
li
{
font-weight: normal;
text-transform: none;
}
.rowitem
{
text-transform: none;
}
}
@media (max-width: 620px) {
li
{
padding-left: 5px;
padding-top: 2px;
padding-bottom: 2px;
height: 23px;
}
ul { height: 24px; }
.menu_left { padding-right: 5px; }
.menu_right { padding-right: 5px; }
.menu_create_topic { display: none;}
.hide_on_mobile { display: none; }
}
@media (max-width: 470px) {
.menu_overview { display: none; }
.menu_profile { display: none; }
.hide_on_micro { display: none; }
.post_container {
overflow: visible !important;
}
.post_item {
background-position: 0px 2px !important;
background-size: 64px 64px !important;
padding-left: 2px !important;
min-height: 96px;
position: relative !important;
}
.post_item > .user_content {
margin-left: 75px !important;
width: 100% !important;
}
.post_item > .mod_button {
float: right !important;
margin-left: 2px !important;
position: relative;
top: -14px;
}
.post_item > .real_username {
position: absolute;
top: 70px;
float: left;
margin-top: 0px;
padding-top: 3px !important;
margin-right: 2px;
width: 60px;
font-size: 15px;
}
.container { width: 100% !important; }
}

View File

@ -0,0 +1,6 @@
{
"Name": "tempra-simple",
"FriendlyName": "Tempra Simple",
"Version": "0.0.1",
"Creator": "Azareal"
}