add BuildWidget2 to avoid allocing as many strings in templates for docks

dynamic load /topics/ page where possible
reduce boilerplate
This commit is contained in:
Azareal 2020-04-12 15:00:15 +10:00
parent d1506d8567
commit 5fe0c8c95b
6 changed files with 145 additions and 50 deletions

View File

@ -162,11 +162,11 @@ func CompileTemplates() error {
log.Print("Compiling the templates")
// TODO: Implement per-theme template overrides here too
overriden := make(map[string]map[string]bool)
for _, theme := range Themes {
overriden[theme.Name] = make(map[string]bool)
log.Printf("theme.OverridenTemplates: %+v\n", theme.OverridenTemplates)
for _, override := range theme.OverridenTemplates {
overriden[theme.Name][override] = true
for _, th := range Themes {
overriden[th.Name] = make(map[string]bool)
log.Printf("th.OverridenTemplates: %+v\n", th.OverridenTemplates)
for _, override := range th.OverridenTemplates {
overriden[th.Name][override] = true
}
}
log.Printf("overriden: %+v\n", overriden)
@ -175,6 +175,7 @@ func CompileTemplates() error {
Minify: Config.MinifyTemplates,
Debug: Dev.DebugMode,
SuperDebug: Dev.TemplateDebug,
DockToID: DockToID,
}
c := tmpl.NewCTemplateSet("normal")
c.SetConfig(config)
@ -195,13 +196,13 @@ func CompileTemplates() error {
log.Printf("oroots: %+v\n", oroots)
log.Print("Compiling the per-theme templates")
for theme, tmpls := range oroots {
c.ResetLogs("normal-" + theme)
c.SetThemeName(theme)
for th, tmpls := range oroots {
c.ResetLogs("normal-" + th)
c.SetThemeName(th)
c.SetPerThemeTmpls(tmpls)
log.Print("theme: ", theme)
log.Print("th: ", th)
log.Printf("perThemeTmpls: %+v\n", tmpls)
err := compileTemplates(&wg, c, theme)
err := compileTemplates(&wg, c, th)
if err != nil {
return err
}
@ -229,6 +230,7 @@ func compileCommons(c *tmpl.CTemplateSet, head, head2 *Header, forumList []Forum
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}}
o.Add("topics", "c.TopicListPage", topicListPage)
o.Add("topics_mini", "c.TopicListPage", topicListPage)
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}}
@ -472,6 +474,7 @@ func CompileJSTemplates() error {
SkipTmplPtrMap: true,
SkipInitBlock: false,
PackageName: "tmpl",
DockToID: DockToID,
}
c := tmpl.NewCTemplateSet("js")
c.SetConfig(config)

View File

@ -42,6 +42,7 @@ type CTemplateConfig struct {
SkipTmplPtrMap bool
SkipInitBlock bool
PackageName string
DockToID map[string]int
}
// nolint
@ -249,7 +250,7 @@ func Tmpl_` + fname + `(tmpl_i interface{}, w io.Writer) error {
c.fileDir = fileDir
content, err := c.loadTemplate(c.fileDir, name)
if err != nil {
c.detail("bailing out: ", err)
c.detail("bailing out:", err)
return "", "", "", err
}
@ -274,7 +275,7 @@ func (c *CTemplateSet) Compile(name, fileDir, expects string, expectsInt interfa
c.fileDir = fileDir
content, err := c.loadTemplate(c.fileDir, name)
if err != nil {
c.detail("bailing out: ", err)
c.detail("bailing out:", err)
return "", err
}
@ -455,7 +456,7 @@ func (c *CTemplateSet) compile(name, content, expects string, expectsInt interfa
if len(c.langIndexToName) > 0 {
for i, name := range c.langIndexToName {
//l += `"` + name + `"` + ",\n"
if i == 0{
if i == 0 {
l += `"` + name + `"`
} else {
l += `,"` + name + `"`
@ -541,7 +542,8 @@ if !ok {
for fid := 0; len(outBuf) > fid; fid++ {
fr := outBuf[fid]
c.detail(fr.Type + " frame")
if fr.Type == "text" {
switch {
case fr.Type == "text":
c.detail(fr)
oid := fid
c.detail("oid:", oid)
@ -568,14 +570,13 @@ if !ok {
c.detail("post fid:", fid)
}
writeTextFrame(fr.TemplateName, fr.Extra.(int)-skip)
} else if fr.Type == "varsub" || fr.Type == "cvarsub" {
case fr.Type == "varsub" || fr.Type == "cvarsub":
fout += "w.Write(" + fr.Body + ")\n"
} else if fr.Type == "identifier" {
fout += fr.Body
} else if fr.Type == "lang" {
case fr.Type == "lang":
//fout += "w.Write(plist[" + strconv.Itoa(fr.Extra.(int)) + "])\n"
fout += "w.Write(" + fname + "_phrase_arr[" + strconv.Itoa(fr.Extra.(int)) + "])\n"
} else {
//case fr.Type == "identifier":
default:
fout += fr.Body
}
}
@ -587,7 +588,7 @@ if !ok {
}
for _, frag := range c.fragBuf {
c.detail("frag: ", frag)
c.detail("frag:", frag)
if frag.Seen {
c.detail("invisible")
continue
@ -745,7 +746,7 @@ func (c *CTemplateSet) addText(con CContext, text []byte) {
return
}
nodeText := string(text)
c.detail("con.TemplateName: ", con.TemplateName)
c.detail("con.TemplateName:", con.TemplateName)
fragIndex := c.fragmentCursor[con.TemplateName]
_, ok := c.fragOnce[con.TemplateName]
c.fragBuf = append(c.fragBuf, Fragment{nodeText, con.TemplateName, fragIndex, ok})
@ -756,7 +757,7 @@ func (c *CTemplateSet) addText(con CContext, text []byte) {
func (c *CTemplateSet) compileRangeNode(con CContext, node *parse.RangeNode) {
c.dumpCall("compileRangeNode", con, node)
defer c.retCall("compileRangeNode")
c.detail("node.Pipe: ", node.Pipe)
c.detail("node.Pipe:", node.Pipe)
var expr string
var outVal reflect.Value
for _, cmd := range node.Pipe.Cmds {
@ -882,7 +883,7 @@ func (c *CTemplateSet) compileSubSwitch(con CContext, node *parse.CommandNode) {
cur = c.skipStructPointers(cur, id)
c.checkIfValid(cur, con.VarHolder, con.HoldReflect, varBit, multiline)
c.detail("in-loop varBit: " + varBit)
c.detail("in-loop varBit:" + varBit)
if cur.Kind() == reflect.Map {
cur = cur.MapIndex(reflect.ValueOf(id))
varBit += "[\"" + id + "\"]"
@ -927,7 +928,7 @@ func (c *CTemplateSet) compileSubSwitch(con CContext, node *parse.CommandNode) {
}
varBit += cur.Type().Name() + ")"
}
c.detail("End Cycle: ", varBit)
c.detail("End Cycle:", varBit)
}
if multiline {
@ -1026,19 +1027,19 @@ func (c *CTemplateSet) compileIdentSwitchN(con CContext, n *parse.CommandNode) (
}
func (c *CTemplateSet) dumpSymbol(pos int, node *parse.CommandNode, symbol string) {
c.detail("symbol: ", symbol)
c.detail("symbol:", symbol)
c.detail("node.Args[pos+1]", node.Args[pos+1])
c.detail("node.Args[pos+2]", node.Args[pos+2])
}
func (c *CTemplateSet) compareFunc(con CContext, pos int, node *parse.CommandNode, compare string) (out string) {
c.dumpSymbol(pos, node, compare)
return c.compileIfVarSubN(con, node.Args[pos+1].String()) + " " + compare + " " + c.compileIfVarSubN(con, node.Args[pos+2].String())
func (c *CTemplateSet) compareFunc(con CContext, pos int, n *parse.CommandNode, compare string) (out string) {
c.dumpSymbol(pos, n, compare)
return c.compileIfVarSubN(con, n.Args[pos+1].String()) + " " + compare + " " + c.compileIfVarSubN(con, n.Args[pos+2].String())
}
func (c *CTemplateSet) simpleMath(con CContext, pos int, node *parse.CommandNode, symbol string) (out string, val reflect.Value) {
leftParam, val2 := c.compileIfVarSub(con, node.Args[pos+1].String())
rightParam, val3 := c.compileIfVarSub(con, node.Args[pos+2].String())
func (c *CTemplateSet) simpleMath(con CContext, pos int, n *parse.CommandNode, symbol string) (out string, val reflect.Value) {
leftParam, val2 := c.compileIfVarSub(con, n.Args[pos+1].String())
rightParam, val3 := c.compileIfVarSub(con, n.Args[pos+2].String())
if val2.IsValid() {
val = val2
} else if val3.IsValid() {
@ -1048,7 +1049,7 @@ func (c *CTemplateSet) simpleMath(con CContext, pos int, node *parse.CommandNode
numSample := 1
val = reflect.ValueOf(numSample)
}
c.dumpSymbol(pos, node, symbol)
c.dumpSymbol(pos, n, symbol)
return leftParam + " " + symbol + " " + rightParam, val
}
@ -1097,7 +1098,7 @@ ArgLoop:
for pos := 0; pos < len(node.Args); pos++ {
id := node.Args[pos]
c.detail("pos:", pos)
c.detail("ID:", id)
c.detail("id:", id)
switch id.String() {
case "not":
out += "!"
@ -1144,6 +1145,14 @@ ArgLoop:
val = val3
// TODO: Refactor this
if leftParam[0] == '"' {
leftParam = strings.TrimSuffix(strings.TrimPrefix(leftParam, "\""), "\"")
id, ok := c.config.DockToID[leftParam]
if ok {
litString("c.BuildWidget2("+strconv.Itoa(id)+","+rightParam+")", false)
break ArgLoop
}
}
litString("c.BuildWidget("+leftParam+","+rightParam+")", false)
break ArgLoop
case "hasWidgets":
@ -1621,8 +1630,8 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V
}
}
c.detail("varname: ", varname)
c.detail("assLines: ", assLines)
c.detail("varname:", varname)
c.detail("assLines:", assLines)
var base string
switch val.Kind() {
case reflect.Int:
@ -1716,7 +1725,7 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V
c.logger.Println("Unknown Type:", val.Type().Name())
panic("-- I don't know what this variable's type is o.o\n")
}
c.detail("base: ", base)
c.detail("base:", base)
if assLines == "" {
con.Push("varsub", base)
} else {
@ -1893,12 +1902,12 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
c.detailf("c.overridenRoots: %+v\n", c.overridenRoots)
}
func (c *CTemplateSet) loadTemplate(fileDir string, name string) (content string, err error) {
func (c *CTemplateSet) loadTemplate(fileDir, name string) (content string, err error) {
c.dumpCall("loadTemplate", fileDir, name)
c.detail("c.themeName: ", c.themeName)
c.detail("c.themeName:", c.themeName)
if c.themeName != "" {
t := "./themes/" + c.themeName + "/overrides/" + name
c.detail("per-theme override: ", true)
c.detail("per-theme override:", true)
res, err := ioutil.ReadFile(t)
if err == nil {
content = string(res)
@ -1907,13 +1916,13 @@ func (c *CTemplateSet) loadTemplate(fileDir string, name string) (content string
}
return content, nil
}
c.detail("override err: ", err)
c.detail("override err:", err)
}
res, err := ioutil.ReadFile(c.fileDir + "overrides/" + name)
if err != nil {
c.detail("override path: ", c.fileDir+"overrides/"+name)
c.detail("override err: ", err)
c.detail("override path:", c.fileDir+"overrides/"+name)
c.detail("override err:", err)
res, err = ioutil.ReadFile(c.fileDir + name)
if err != nil {
return "", err

View File

@ -43,6 +43,7 @@ type Theme struct {
Tag string
URL string
Docks []string // Allowed Values: leftSidebar, rightSidebar, footer
DocksID []int // Integer versions of Docks to try to get a speed boost in BuildWidget()
Settings map[string]ThemeSetting
IntTmplHandle *htmpl.Template
// TODO: Do we really need both OverridenTemplates AND OverridenMap?
@ -58,6 +59,7 @@ type Theme struct {
// TODO: Implement this
MapTmplToDock map[string]ThemeMapTmplToDock // map[dockName]data
RunOnDock func(string) string //(dock string) (sbody string)
RunOnDockID func(int) string //(dock int) (sbody string)
// This variable should only be set and unset by the system, not the theme meta file
// TODO: Should we phase out Active and make the default theme store the primary source of truth?
@ -381,6 +383,23 @@ func (t Theme) BuildDock(dock string) (sbody string) {
return ""
}
func (t Theme) HasDockByID(id int) bool {
for _, dock := range t.DocksID {
if dock == id {
return true
}
}
return false
}
func (t Theme) BuildDockByID(id int) (sbody string) {
runOnDock := t.RunOnDockID
if runOnDock != nil {
return runOnDock(id)
}
return ""
}
type GzipResponseWriter struct {
io.Writer
http.ResponseWriter

View File

@ -76,7 +76,7 @@ func NewThemeList() (themes ThemeList, err error) {
return themes, err
}
theme := &Theme{Name: ""}
theme := &Theme{}
err = json.Unmarshal(themeFile, theme)
if err != nil {
return themes, err
@ -97,7 +97,7 @@ func NewThemeList() (themes ThemeList, err error) {
if err != nil {
return themes, err
}
theme = &Theme{Name: "", Path: theme.Path}
theme = &Theme{Path: theme.Path}
err = json.Unmarshal(themeFile, theme)
if err != nil {
return themes, err
@ -179,21 +179,30 @@ func NewThemeList() (themes ThemeList, err error) {
for i, res := range theme.Resources {
ext := filepath.Ext(res.Name)
if ext == ".css" {
switch ext {
case ".css":
res.Type = ResTypeSheet
} else if ext == ".js" {
case ".js":
res.Type = ResTypeScript
}
if res.Location == "global" {
switch res.Location {
case "global":
res.LocID = LocGlobal
} else if res.Location == "frontend" {
case "frontend":
res.LocID = LocFront
} else if res.Location == "panel" {
case "panel":
res.LocID = LocPanel
}
theme.Resources[i] = res
}
for _, dock := range theme.Docks {
id, ok := DockToID[dock]
if ok {
theme.DocksID = append(theme.DocksID, id)
}
}
// TODO: Bind the built template, or an interpreted one for any dock overrides this theme has
themes[theme.Name] = theme

View File

@ -221,6 +221,61 @@ func BuildWidget(dock string, h *Header) (sbody string) {
return sbody
}
var DockToID = map[string]int{
"leftOfNav": 0,
"rightOfNav": 1,
"topMenu": 2,
"rightSidebar": 3,
"footer": 4,
}
func BuildWidget2(dock int, h *Header) (sbody string) {
if !h.Theme.HasDockByID(dock) {
return ""
}
// Let themes forcibly override this slot
sbody = h.Theme.BuildDockByID(dock)
if sbody != "" {
return sbody
}
var widgets []*Widget
switch dock {
case 0:
widgets = Docks.LeftOfNav
case 1:
widgets = Docks.RightOfNav
case 2:
// 1 = id for the default menu
mhold, err := Menus.Get(1)
if err == nil {
err := mhold.Build(h.Writer, h.CurrentUser, h.Path)
if err != nil {
LogError(err)
}
}
return ""
case 3:
widgets = Docks.RightSidebar.Items
case 4:
widgets = Docks.Footer.Items
}
for _, widget := range widgets {
if !widget.Enabled {
continue
}
if widget.Allowed(h.Zone, h.ZoneID) {
item, err := widget.Build(h)
if err != nil {
LogError(err)
}
sbody += item
}
}
return sbody
}
func getDockWidgets(dock string) (widgets []*Widget, err error) {
rows, err := widgetStmts.getDockList.Query(dock)
if err != nil {

View File

@ -35,4 +35,4 @@
</form>
</div>
</main>
{{template "footer.html" . }}
{{template "footer.html" . }}