Speed up template compilation by not building the same parse trees multiple times.

Compile panel_debug.
Add the ability to print int8, int16, int32, uint, uint8, uint16, uint32 and uint64 in compiled templates.
Add the ability to pass string nodes to subtemplates in the template compiler.
Fix bunit in the template compiler.

Shorten some things.
This commit is contained in:
Azareal 2019-10-13 08:49:08 +10:00
parent f76af39a11
commit df6e268a06
5 changed files with 120 additions and 61 deletions

View File

@ -6,14 +6,16 @@ import (
"io" "io"
"log" "log"
"path/filepath" "path/filepath"
"runtime"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/Azareal/Gosora/common/alerts" "github.com/Azareal/Gosora/common/alerts"
"github.com/Azareal/Gosora/common/phrases" p "github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/common/templates" "github.com/Azareal/Gosora/common/templates"
"github.com/Azareal/Gosora/query_gen"
) )
var Ctemplates []string // TODO: Use this to filter out top level templates we don't need var Ctemplates []string // TODO: Use this to filter out top level templates we don't need
@ -184,8 +186,7 @@ func CompileTemplates() error {
log.Print("Compiling the default templates") log.Print("Compiling the default templates")
var wg sync.WaitGroup var wg sync.WaitGroup
err := compileTemplates(&wg, c, "") if err := compileTemplates(&wg, c, ""); err != nil {
if err != nil {
return err return err
} }
oroots := c.GetOverridenRoots() oroots := c.GetOverridenRoots()
@ -198,7 +199,7 @@ func CompileTemplates() error {
c.SetPerThemeTmpls(tmpls) c.SetPerThemeTmpls(tmpls)
log.Print("theme: ", theme) log.Print("theme: ", theme)
log.Printf("perThemeTmpls: %+v\n", tmpls) log.Printf("perThemeTmpls: %+v\n", tmpls)
err = compileTemplates(&wg, c, theme) err := compileTemplates(&wg, c, theme)
if err != nil { if err != nil {
return err return err
} }
@ -207,30 +208,30 @@ func CompileTemplates() error {
return nil return nil
} }
func compileCommons(c *tmpl.CTemplateSet, header *Header, header2 *Header, forumList []Forum, out TItemHold) error { func compileCommons(c *tmpl.CTemplateSet, head *Header, head2 *Header, forumList []Forum, o TItemHold) error {
// TODO: Add support for interface{}s // TODO: Add support for interface{}s
_, user2, user3 := tmplInitUsers() _, user2, user3 := tmplInitUsers()
now := time.Now() now := time.Now()
// Convienience function to save a line here and there // Convienience function to save a line here and there
htitle := func(name string) *Header { htitle := func(name string) *Header {
header.Title = name head.Title = name
return header return head
} }
/*htitle2 := func(name string) *Header { /*htitle2 := func(name string) *Header {
header2.Title = name head2.Title = name
return header2 return head2
}*/ }*/
var topicsList []*TopicsRow var topicsList []*TopicsRow
topicsList = append(topicsList, &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, 1, 0, "classname", 0, "", &user2, "", 0, &user3, "General", "/forum/general.2", nil}) topicsList = append(topicsList, &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, 1, 0, "classname", 0, "", &user2, "", 0, &user3, "General", "/forum/general.2", nil})
topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, Paginator{[]int{1}, 1, 1}} topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, Paginator{[]int{1}, 1, 1}}
out.Add("topics", "c.TopicListPage", topicListPage) o.Add("topics", "c.TopicListPage", topicListPage)
forumItem := BlankForum(1, "general-forum.1", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0) forumItem := BlankForum(1, "general-forum.1", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0)
forumPage := ForumPage{htitle("General Forum"), topicsList, forumItem, Paginator{[]int{1}, 1, 1}} forumPage := ForumPage{htitle("General Forum"), topicsList, forumItem, Paginator{[]int{1}, 1, 1}}
out.Add("forum", "c.ForumPage", forumPage) o.Add("forum", "c.ForumPage", forumPage)
out.Add("forums", "c.ForumsPage", ForumsPage{htitle("Forum List"), forumList}) o.Add("forums", "c.ForumsPage", ForumsPage{htitle("Forum List"), forumList})
poll := Poll{ID: 1, Type: 0, Options: map[int]string{0: "Nothing", 1: "Something"}, Results: map[int]int{0: 5, 1: 2}, QuickOptions: []PollOption{ 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{0, "Nothing"},
@ -247,8 +248,8 @@ func compileCommons(c *tmpl.CTemplateSet, header *Header, header2 *Header, forum
replyList = append(replyList, ru) replyList = append(replyList, ru)
tpage := TopicPage{htitle("Topic Name"), replyList, topic, &Forum{ID: 1, Name: "Hahaha"}, poll, Paginator{[]int{1}, 1, 1}} tpage := TopicPage{htitle("Topic Name"), replyList, topic, &Forum{ID: 1, Name: "Hahaha"}, poll, Paginator{[]int{1}, 1, 1}}
tpage.Forum.Link = BuildForumURL(NameToSlug(tpage.Forum.Name), tpage.Forum.ID) tpage.Forum.Link = BuildForumURL(NameToSlug(tpage.Forum.Name), tpage.Forum.ID)
out.Add("topic", "c.TopicPage", tpage) o.Add("topic", "c.TopicPage", tpage)
out.Add("topic_alt", "c.TopicPage", tpage) o.Add("topic_alt", "c.TopicPage", tpage)
return nil return nil
} }
@ -362,6 +363,16 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
t.AddStd("panel", "c.Panel", Panel{basePage, "panel_dashboard_right", "", "panel_dashboard", inter}) t.AddStd("panel", "c.Panel", Panel{basePage, "panel_dashboard_right", "", "panel_dashboard", inter})
ges := []GridElement{GridElement{"","", "", 1, "grid_istat", "", "", ""}} ges := []GridElement{GridElement{"","", "", 1, "grid_istat", "", "", ""}}
t.AddStd("panel_dashboard", "c.DashGrids", DashGrids{ges,ges}) t.AddStd("panel_dashboard", "c.DashGrids", DashGrids{ges,ges})
goVersion := runtime.Version()
dbVersion := qgen.Builder.DbVersion()
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
debugCache := DebugPageCache{1, 1, 1, 2, 2, 2, true}
debugDatabase := DebugPageDatabase{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
debugDisk := DebugPageDisk{1,1,1,1,1,1}
dpage := PanelDebugPage{basePage, goVersion, dbVersion, "0s", 1, qgen.Builder.GetAdapter().GetName(), 1, 1, memStats, debugCache, debugDatabase, debugDisk}
t.AddStd("panel_debug", "c.PanelDebugPage", dpage)
//t.AddStd("panel_analytics", "c.PanelAnalytics", Panel{basePage, "panel_dashboard_right","panel_dashboard", inter}) //t.AddStd("panel_analytics", "c.PanelAnalytics", Panel{basePage, "panel_dashboard_right","panel_dashboard", inter})
writeTemplate := func(name string, content interface{}) { writeTemplate := func(name string, content interface{}) {
@ -732,7 +743,7 @@ func initDefaultTmplFuncMap() {
panic("phraseNameInt is not a string") panic("phraseNameInt is not a string")
} }
// TODO: Log non-existent phrases? // TODO: Log non-existent phrases?
return template.HTML(phrases.GetTmplPhrase(phraseName)) return template.HTML(p.GetTmplPhrase(phraseName))
} }
// TODO: Implement this in the template generator too // TODO: Implement this in the template generator too
@ -743,7 +754,7 @@ func initDefaultTmplFuncMap() {
} }
// TODO: Log non-existent phrases? // TODO: Log non-existent phrases?
// TODO: Optimise TmplPhrasef so we don't use slow Sprintf there // TODO: Optimise TmplPhrasef so we don't use slow Sprintf there
return template.HTML(phrases.GetTmplPhrasef(phraseName, args...)) return template.HTML(p.GetTmplPhrasef(phraseName, args...))
} }
fmap["level"] = func(levelInt interface{}) interface{} { fmap["level"] = func(levelInt interface{}) interface{} {
@ -751,7 +762,7 @@ func initDefaultTmplFuncMap() {
if !ok { if !ok {
panic("levelInt is not an integer") panic("levelInt is not an integer")
} }
return template.HTML(phrases.GetLevelPhrase(level)) return template.HTML(p.GetLevelPhrase(level))
} }
fmap["bunit"] = func(byteInt interface{}) interface{} { fmap["bunit"] = func(byteInt interface{}) interface{} {

View File

@ -218,18 +218,15 @@ import "errors"
if !c.config.SkipInitBlock { if !c.config.SkipInitBlock {
stub += "// nolint\nfunc init() {\n" stub += "// nolint\nfunc init() {\n"
if !c.config.SkipHandles && c.themeName == "" { if !c.config.SkipHandles && c.themeName == "" {
stub += "\tc.Template_" + fname + "_handle = Template_" + fname + "\n" stub += "\tc.Template_" + fname + "_handle = Template_" + fname + "\n"
stub += "\tc.Ctemplates = append(c.Ctemplates,\"" + fname + "\")\n" stub += "\tc.Ctemplates = append(c.Ctemplates,\"" + fname + "\")\n"
} }
if !c.config.SkipTmplPtrMap { if !c.config.SkipTmplPtrMap {
stub += "tmpl := Template_" + fname + "\n" stub += "tmpl := Template_" + fname + "\n"
stub += "\tc.TmplPtrMap[\"" + fname + "\"] = &tmpl\n" stub += "\tc.TmplPtrMap[\"" + fname + "\"] = &tmpl\n"
stub += "\tc.TmplPtrMap[\"o_" + fname + "\"] = tmpl\n" stub += "\tc.TmplPtrMap[\"o_" + fname + "\"] = tmpl\n"
} }
stub += "}\n\n" stub += "}\n\n"
} }
@ -287,8 +284,7 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
if r := recover(); r != nil { if r := recover(); r != nil {
fmt.Println(r) fmt.Println(r)
debug.PrintStack() debug.PrintStack()
err := c.loggerf.Sync() if err := c.loggerf.Sync(); err != nil {
if err != nil {
fmt.Println(err) fmt.Println(err)
} }
log.Fatal("") log.Fatal("")
@ -311,13 +307,14 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
c.localDispStructIndex = 0 c.localDispStructIndex = 0
c.stats = make(map[string]int) c.stats = make(map[string]int)
tree := parse.New(name, c.funcMap) //tree := parse.New(name, c.funcMap)
treeSet := make(map[string]*parse.Tree) //treeSet := make(map[string]*parse.Tree)
tree, err = tree.Parse(content, "{{", "}}", treeSet, c.funcMap) treeSet, err := parse.Parse(name, content, "{{", "}}", c.funcMap)
if err != nil { if err != nil {
return "", err return "", err
} }
c.detail(name) c.detail(name)
c.detailf("treeSet: %+v\n", treeSet)
fname := strings.TrimSuffix(name, filepath.Ext(name)) fname := strings.TrimSuffix(name, filepath.Ext(name))
if c.themeName != "" { if c.themeName != "" {
@ -374,8 +371,21 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
TemplateName: fname, TemplateName: fname,
OutBuf: &outBuf, OutBuf: &outBuf,
} }
c.templateList = map[string]*parse.Tree{fname: tree}
c.detail(c.templateList) c.templateList = map[string]*parse.Tree{}
for nname, tree := range treeSet {
if name == nname {
c.templateList[fname] = tree
} else {
if !strings.HasPrefix(nname, ".html") {
c.templateList[nname] = tree
} else {
c.templateList[strings.TrimSuffix(nname, ".html")] = tree
}
}
}
c.detailf("c.templateList: %+v\n", c.templateList)
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{".", con.VarHolder, con.HoldReflect} c.localVars[fname]["."] = VarItemReflect{".", con.VarHolder, con.HoldReflect}
@ -392,8 +402,14 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
//} //}
//c.detailf("c: %+v\n", c) //c.detailf("c: %+v\n", c)
c.detailf("name: %+v\n", name)
c.detailf("fname: %+v\n", fname)
startIndex := con.StartTemplate("") startIndex := con.StartTemplate("")
c.rootIterate(c.templateList[fname], con) ttree := c.templateList[fname]
if ttree == nil {
panic("ttree is nil")
}
c.rootIterate(ttree, con)
con.EndTemplate("") con.EndTemplate("")
c.afterTemplate(con, startIndex) c.afterTemplate(con, startIndex)
//c.templateFragmentCount[fname] = c.fragmentCursor[fname] + 1 //c.templateFragmentCount[fname] = c.fragmentCursor[fname] + 1
@ -574,6 +590,10 @@ w.Write([]byte(`, " + ", -1)
func (c *CTemplateSet) rootIterate(tree *parse.Tree, con CContext) { func (c *CTemplateSet) rootIterate(tree *parse.Tree, con CContext) {
c.dumpCall("rootIterate", tree, con) c.dumpCall("rootIterate", tree, con)
if tree.Root == nil {
c.detailf("tree: %+v\n", tree)
panic("tree root node is empty")
}
c.detail(tree.Root) c.detail(tree.Root)
for _, node := range tree.Root.Nodes { for _, node := range tree.Root.Nodes {
c.detail("Node:", node.String()) c.detail("Node:", node.String())
@ -1195,8 +1215,9 @@ ArgLoop:
} }
leftParam, _ := c.compileIfVarSub(con, leftOperand) leftParam, _ := c.compileIfVarSub(con, leftOperand)
out = "{\nbyteFloat, unit := c.ConvertByteUnit(float64(" + leftParam + "))\n" out = "{\nbyteFloat, unit := c.ConvertByteUnit(float64(" + leftParam + "))\n"
out += "w.Write(fmt.Sprintf(\"%.1f\", byteFloat) + unit)\n" out += "w.Write(StringToBytes(fmt.Sprintf(\"%.1f\", byteFloat) + unit))\n}\n"
literal = true literal = true
c.importMap["fmt"] = "fmt"
break ArgLoop break ArgLoop
case "abstime": case "abstime":
// TODO: Implement level literals // TODO: Implement level literals
@ -1601,9 +1622,18 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V
if c.guestOnly && base == "StringToBytes("+con.RootHolder+".CurrentUser.Session))" { if c.guestOnly && base == "StringToBytes("+con.RootHolder+".CurrentUser.Session))" {
return return
} }
case reflect.Int8, reflect.Int16, reflect.Int32:
c.importMap["strconv"] = "strconv"
base = "StringToBytes(strconv.FormatInt(int64(" + varname + "), 10))"
case reflect.Int64: case reflect.Int64:
c.importMap["strconv"] = "strconv" c.importMap["strconv"] = "strconv"
base = "StringToBytes(strconv.FormatInt(" + varname + ", 10))" base = "StringToBytes(strconv.FormatInt(" + varname + ", 10))"
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
c.importMap["strconv"] = "strconv"
base = "StringToBytes(strconv.FormatUint(uint64(" + varname + "), 10))"
case reflect.Uint64:
c.importMap["strconv"] = "strconv"
base = "StringToBytes(strconv.FormatUint(" + varname + ", 10))"
case reflect.Struct: case reflect.Struct:
// TODO: Avoid clashing with other packages which have structs named Time // TODO: Avoid clashing with other packages which have structs named Time
if val.Type().Name() == "Time" { if val.Type().Name() == "Time" {
@ -1638,19 +1668,6 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
defer c.retCall("compileSubTemplate") defer c.retCall("compileSubTemplate")
c.detail("Template Node: ", node.Name) c.detail("Template Node: ", node.Name)
// TODO: Cascade errors back up the tree to the caller?
content, err := c.loadTemplate(c.fileDir, node.Name)
if err != nil {
c.logger.Fatal(err)
}
tree := parse.New(node.Name, c.funcMap)
var treeSet = make(map[string]*parse.Tree)
tree, err = tree.Parse(content, "{{", "}}", treeSet, c.funcMap)
if err != nil {
c.logger.Fatal(err)
}
fname := strings.TrimSuffix(node.Name, filepath.Ext(node.Name)) fname := strings.TrimSuffix(node.Name, filepath.Ext(node.Name))
if c.themeName != "" { if c.themeName != "" {
_, ok := c.perThemeTmpls[fname] _, ok := c.perThemeTmpls[fname]
@ -1666,6 +1683,36 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
fname += "_member" fname += "_member"
} }
_, ok := c.templateList[fname]
if !ok {
// TODO: Cascade errors back up the tree to the caller?
content, err := c.loadTemplate(c.fileDir, node.Name)
if err != nil {
c.logger.Fatal(err)
}
//tree := parse.New(node.Name, c.funcMap)
//treeSet := make(map[string]*parse.Tree)
treeSet, err := parse.Parse(node.Name, content, "{{", "}}", c.funcMap)
if err != nil {
c.logger.Fatal(err)
}
c.detailf("treeSet: %+v\n", treeSet)
for nname, tree := range treeSet {
if node.Name == nname {
c.templateList[fname] = tree
} else {
if !strings.HasPrefix(nname, ".html") {
c.templateList[nname] = tree
} else {
c.templateList[strings.TrimSuffix(nname, ".html")] = tree
}
}
}
c.detailf("c.templateList: %+v\n", c.templateList)
}
con := pcon con := pcon
con.VarHolder = "tmpl_" + fname + "_vars" con.VarHolder = "tmpl_" + fname + "_vars"
con.TemplateName = fname con.TemplateName = fname
@ -1675,7 +1722,6 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
case *parse.FieldNode: case *parse.FieldNode:
// TODO: Incomplete but it should cover the basics // TODO: Incomplete but it should cover the basics
cur := pcon.HoldReflect cur := pcon.HoldReflect
var varBit string var varBit string
if cur.Kind() == reflect.Interface { if cur.Kind() == reflect.Interface {
cur = cur.Elem() cur = cur.Elem()
@ -1707,6 +1753,11 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
} }
con.VarHolder = pcon.VarHolder + varBit con.VarHolder = pcon.VarHolder + varBit
con.HoldReflect = cur con.HoldReflect = cur
case *parse.StringNode:
//con.VarHolder = pcon.VarHolder
//con.HoldReflect = pcon.HoldReflect
con.VarHolder = p.Quoted
con.HoldReflect = reflect.ValueOf(p.Quoted)
case *parse.DotNode: case *parse.DotNode:
con.VarHolder = pcon.VarHolder con.VarHolder = pcon.VarHolder
con.HoldReflect = pcon.HoldReflect con.HoldReflect = pcon.HoldReflect
@ -1730,7 +1781,7 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
} }
} }
c.templateList[fname] = tree //c.templateList[fname] = tree
subtree := c.templateList[fname] subtree := c.templateList[fname]
c.detail("subtree.Root", subtree.Root) c.detail("subtree.Root", subtree.Root)
c.localVars[fname] = make(map[string]VarItemReflect) c.localVars[fname] = make(map[string]VarItemReflect)
@ -1746,9 +1797,7 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
c.rootIterate(subtree, con) c.rootIterate(subtree, con)
con.EndTemplate(endBit) con.EndTemplate(endBit)
//c.templateFragmentCount[fname] = c.fragmentCursor[fname] + 1 //c.templateFragmentCount[fname] = c.fragmentCursor[fname] + 1
if _, ok := c.fragOnce[fname]; !ok {
_, ok := c.fragOnce[fname]
if !ok {
c.fragOnce[fname] = true c.fragOnce[fname] = true
} }
@ -1785,11 +1834,11 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
func (c *CTemplateSet) loadTemplate(fileDir string, name string) (content string, err error) { func (c *CTemplateSet) loadTemplate(fileDir string, name string) (content string, err error) {
c.dumpCall("loadTemplate", fileDir, name) c.dumpCall("loadTemplate", fileDir, name)
c.detail("c.themeName: ", c.themeName) c.detail("c.themeName: ", c.themeName)
if c.themeName != "" { if c.themeName != "" {
c.detail("per-theme override: ", "./themes/"+c.themeName+"/overrides/"+name) t := "./themes/" + c.themeName + "/overrides/" + name
res, err := ioutil.ReadFile("./themes/" + c.themeName + "/overrides/" + name) c.detail("per-theme override: ", true)
res, err := ioutil.ReadFile(t)
if err == nil { if err == nil {
content = string(res) content = string(res)
if c.config.Minify { if c.config.Minify {
@ -1820,11 +1869,10 @@ func (c *CTemplateSet) afterTemplate(con CContext, startIndex int) {
c.dumpCall("afterTemplate", con, startIndex) c.dumpCall("afterTemplate", con, startIndex)
defer c.retCall("afterTemplate") defer c.retCall("afterTemplate")
var loopDepth = 0 loopDepth := 0
var outBuf = *con.OutBuf var outBuf = *con.OutBuf
var varcounts = make(map[string]int) varcounts := make(map[string]int)
var loopStart = startIndex loopStart := startIndex
if outBuf[startIndex].Type == "startloop" && (len(outBuf) > startIndex+1) { if outBuf[startIndex].Type == "startloop" && (len(outBuf) > startIndex+1) {
loopStart++ loopStart++
} }
@ -1852,7 +1900,7 @@ func (c *CTemplateSet) afterTemplate(con CContext, startIndex int) {
var varstr string var varstr string
var i int var i int
var varmap = make(map[string]int) varmap := make(map[string]int)
for name, count := range varcounts { for name, count := range varcounts {
if count > 1 { if count > 1 {
varstr += "var cached_var_" + strconv.Itoa(i) + " = " + name + "\n" varstr += "var cached_var_" + strconv.Itoa(i) + " = " + name + "\n"

View File

@ -18,10 +18,10 @@ func Debug(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
goVersion := runtime.Version() goVersion := runtime.Version()
dbVersion := qgen.Builder.DbVersion() dbVersion := qgen.Builder.DbVersion()
var uptime string
upDuration := time.Since(c.StartTime) upDuration := time.Since(c.StartTime)
hours := int(upDuration.Hours()) hours := int(upDuration.Hours())
minutes := int(upDuration.Minutes()) minutes := int(upDuration.Minutes())
var uptime string
if hours > 24 { if hours > 24 {
days := hours / 24 days := hours / 24
hours -= days * 24 hours -= days * 24
@ -63,7 +63,7 @@ func Debug(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
debugCache := c.DebugPageCache{tlen, ulen, rlen, tcap, ucap, rcap, topicListThawed} debugCache := c.DebugPageCache{tlen, ulen, rlen, tcap, ucap, rcap, topicListThawed}
var fErr error var fErr error
var count = func(tbl string) int { count := func(tbl string) int {
if fErr != nil { if fErr != nil {
return 0 return 0
} }
@ -96,7 +96,7 @@ func Debug(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
debugDatabase := c.DebugPageDatabase{c.Topics.Count(),c.Users.Count(),c.Rstore.Count(),c.Prstore.Count(),c.Activity.Count(),c.Likes.Count(),attachs,polls,loginLogs,regLogs,modLogs,adminLogs,views,viewsAgents,viewsForums,viewsLangs,viewsReferrers,viewsSystems,postChunks,topicChunks} debugDatabase := c.DebugPageDatabase{c.Topics.Count(),c.Users.Count(),c.Rstore.Count(),c.Prstore.Count(),c.Activity.Count(),c.Likes.Count(),attachs,polls,loginLogs,regLogs,modLogs,adminLogs,views,viewsAgents,viewsForums,viewsLangs,viewsReferrers,viewsSystems,postChunks,topicChunks}
var dirSize = func(path string) int { dirSize := func(path string) int {
if fErr != nil { if fErr != nil {
return 0 return 0
} }

View File

@ -19,7 +19,7 @@
</div> </div>
<div class="formrow"> <div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_user_name"}}</a></div> <div class="formitem formlabel"><a>{{lang "panel_user_name"}}</a></div>
<div class="formitem"><input form="user_form" name="user-name" type="text" value="{{.Something.Name}}" placeholder="{{lang "panel_user_name_placeholder"}}" /></div> <div class="formitem"><input form="user_form" name="user-name" type="text" value="{{.Something.Name}}" placeholder="{{lang "panel_user_name_placeholder"}}" autocomplete="off" /></div>
</div> </div>
{{if .CurrentUser.Perms.EditUserPassword}}<div class="formrow"> {{if .CurrentUser.Perms.EditUserPassword}}<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_user_password"}}</a></div> <div class="formitem formlabel"><a>{{lang "panel_user_password"}}</a></div>
@ -34,7 +34,7 @@
<div class="formitem formlabel"><a>{{lang "panel_user_group"}}</a></div> <div class="formitem formlabel"><a>{{lang "panel_user_group"}}</a></div>
<div class="formitem"> <div class="formitem">
<select form="user_form" name="user-group"> <select form="user_form" name="user-group">
{{range .ItemList}}<option {{if eq .ID $.Something.Group}}selected {{end}}value="{{.ID}}">{{.Name}}</option>{{end}} {{range .ItemList}}<option{{if eq .ID $.Something.Group}} selected{{end}} value="{{.ID}}">{{.Name}}</option>{{end}}
</select> </select>
</div> </div>
</div>{{end}} </div>{{end}}