Reduce bandwidth usage for client templates.
Add js and ptmpl (stub) template functions. Simple constant folding for true / false values in templates. Use empty string instead of 0 for poll vote ips when DisablePollIP is enabled. Shorten some things.
This commit is contained in:
parent
7e3cd48284
commit
363826624f
@ -126,10 +126,10 @@ func LogWarning(err error, extra ...string) {
|
||||
}
|
||||
|
||||
func errorHeader(w http.ResponseWriter, user User, title string) *Header {
|
||||
header := DefaultHeader(w, user)
|
||||
header.Title = title
|
||||
header.Zone = "error"
|
||||
return header
|
||||
h := DefaultHeader(w, user)
|
||||
h.Title = title
|
||||
h.Zone = "error"
|
||||
return h
|
||||
}
|
||||
|
||||
// TODO: Dump the request?
|
||||
@ -400,4 +400,4 @@ func handleErrorTemplate(w http.ResponseWriter, r *http.Request, pi ErrorPage) {
|
||||
}
|
||||
|
||||
// Alias of routes.renderTemplate
|
||||
var RenderTemplateAlias func(tmplName string, hookName string, w http.ResponseWriter, r *http.Request, header *Header, pi interface{}) error
|
||||
var RenderTemplateAlias func(tmplName, hookName string, w http.ResponseWriter, r *http.Request, header *Header, pi interface{}) error
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Azareal/Gosora/tmpl_client"
|
||||
tmpl "github.com/Azareal/Gosora/tmpl_client"
|
||||
)
|
||||
|
||||
type SFileList map[string]SFile
|
||||
@ -28,11 +28,11 @@ type SFile struct {
|
||||
Data []byte
|
||||
GzipData []byte
|
||||
Sha256 string
|
||||
OName string
|
||||
OName string
|
||||
Pos int64
|
||||
Length int64
|
||||
GzipLength int64
|
||||
StrGzipLength string
|
||||
StrGzipLength string
|
||||
Mimetype string
|
||||
Info os.FileInfo
|
||||
FormattedModTime string
|
||||
@ -70,7 +70,7 @@ func (list SFileList) JSTmplInit() error {
|
||||
data = data[startIndex-len([]byte("if(tmplInits===undefined)")):]
|
||||
data = replace(data, "// nolint", "")
|
||||
data = replace(data, "func ", "function ")
|
||||
data = replace(data, " error {\n", " {\nlet out = \"\"\n")
|
||||
data = replace(data, " error {\n", " {\nlet o = \"\"\n")
|
||||
funcIndex, hasFunc := skipAllUntilCharsExist(data, 0, []byte("function Template_"))
|
||||
if !hasFunc {
|
||||
return errors.New("no template function found")
|
||||
@ -175,9 +175,9 @@ func (list SFileList) JSTmplInit() error {
|
||||
}
|
||||
})
|
||||
data = replace(data, "for _, item := range ", "for(item of ")
|
||||
data = replace(data, "w.Write([]byte(", "out += ")
|
||||
data = replace(data, "w.Write(StringToBytes(", "out += ")
|
||||
data = replace(data, "w.Write(", "out += ")
|
||||
data = replace(data, "w.Write([]byte(", "o += ")
|
||||
data = replace(data, "w.Write(StringToBytes(", "o += ")
|
||||
data = replace(data, "w.Write(", "o += ")
|
||||
data = replace(data, "+= c.", "+= ")
|
||||
data = replace(data, "strconv.Itoa(", "")
|
||||
data = replace(data, "strconv.FormatInt(", "")
|
||||
@ -186,7 +186,7 @@ func (list SFileList) JSTmplInit() error {
|
||||
data = replace(data, ", 10;", "")
|
||||
data = replace(data, "var plist = GetTmplPhrasesBytes("+shortName+"_tmpl_phrase_id)", "const plist = tmplPhrases[\""+tmplName+"\"];")
|
||||
data = replace(data, "var cached_var_", "let cached_var_")
|
||||
data = replace(data, `tmpl_`+shortName+`_vars, ok := tmpl_`+shortName+`_i.`, `/*`)
|
||||
data = replace(data, `tmpl_vars, ok := tmpl_i.`, `/*`)
|
||||
data = replace(data, "[]byte(", "")
|
||||
data = replace(data, "StringToBytes(", "")
|
||||
data = replace(data, "RelativeTime(tmpl_"+shortName+"_vars.", "tmpl_"+shortName+"_vars.Relative")
|
||||
@ -194,7 +194,7 @@ func (list SFileList) JSTmplInit() error {
|
||||
data = replace(data, ".Format(\"2006-01-02 15:04:05\"", "")
|
||||
data = replace(data, ", 10", "")
|
||||
data = replace(data, "if ", "if(")
|
||||
data = replace(data, "return nil", "return out")
|
||||
data = replace(data, "return nil", "return o")
|
||||
data = replace(data, " )", ")")
|
||||
data = replace(data, " \n", "\n")
|
||||
data = replace(data, "\n", ";\n")
|
||||
@ -212,10 +212,12 @@ func (list SFileList) JSTmplInit() error {
|
||||
|
||||
fragset := tmpl.GetFrag(shortName)
|
||||
if fragset != nil {
|
||||
sfrags := []byte("let " + shortName + "_frags = [];\n")
|
||||
sfrags := []byte("let " + shortName + "_frags = [\n")
|
||||
for _, frags := range fragset {
|
||||
sfrags = append(sfrags, []byte(shortName+"_frags.push(`"+string(frags)+"`);\n")...)
|
||||
//sfrags = append(sfrags, []byte(shortName+"_frags.push(`"+string(frags)+"`);\n")...)
|
||||
sfrags = append(sfrags, []byte("\t`"+string(frags)+"`,\n")...)
|
||||
}
|
||||
sfrags = append(sfrags, []byte("];\n")...)
|
||||
data = append(sfrags, data...)
|
||||
}
|
||||
data = replace(data, "\n;", "\n")
|
||||
@ -240,7 +242,7 @@ func (list SFileList) JSTmplInit() error {
|
||||
hasher.Write(data)
|
||||
checksum := hex.EncodeToString(hasher.Sum(nil))
|
||||
|
||||
list.Set("/s/"+path, SFile{data, gzipData, checksum,path + "?h=" + checksum, 0, int64(len(data)), int64(len(gzipData)),strconv.Itoa(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||
list.Set("/s/"+path, SFile{data, gzipData, checksum, path + "?h=" + checksum, 0, int64(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||
|
||||
DebugLogf("Added the '%s' static file.", path)
|
||||
return nil
|
||||
@ -285,7 +287,7 @@ func (list SFileList) Init() error {
|
||||
}
|
||||
}
|
||||
|
||||
list.Set("/s/"+path, SFile{data, gzipData, checksum,path + "?h=" + checksum, 0, int64(len(data)), int64(len(gzipData)),strconv.Itoa(len(gzipData)), mimetype, f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||
list.Set("/s/"+path, SFile{data, gzipData, checksum, path + "?h=" + checksum, 0, int64(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), mimetype, f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||
|
||||
DebugLogf("Added the '%s' static file.", path)
|
||||
return nil
|
||||
@ -318,7 +320,7 @@ func (list SFileList) Add(path, prefix string) error {
|
||||
hasher.Write(data)
|
||||
checksum := hex.EncodeToString(hasher.Sum(nil))
|
||||
|
||||
list.Set("/s"+path, SFile{data, gzipData, checksum,path + "?h=" + checksum, 0, int64(len(data)), int64(len(gzipData)),strconv.Itoa(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||
list.Set("/s"+path, SFile{data, gzipData, checksum, path + "?h=" + checksum, 0, int64(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||
|
||||
DebugLogf("Added the '%s' static file", path)
|
||||
return nil
|
||||
|
@ -13,8 +13,8 @@ var FPStore ForumPermsStore
|
||||
type ForumPermsStore interface {
|
||||
Init() error
|
||||
GetAllMap() (bigMap map[int]map[int]*ForumPerms)
|
||||
Get(fid, gid int) (fperms *ForumPerms, err error)
|
||||
GetCopy(fid, gid int) (fperms ForumPerms, err error)
|
||||
Get(fid, gid int) (fp *ForumPerms, err error)
|
||||
GetCopy(fid, gid int) (fp ForumPerms, err error)
|
||||
ReloadAll() error
|
||||
Reload(id int) error
|
||||
}
|
||||
@ -193,7 +193,7 @@ func (s *MemoryForumPermsStore) GetAllMap() (bigMap map[int]map[int]*ForumPerms)
|
||||
// TODO: Add a hook here and have plugin_guilds use it
|
||||
// TODO: Check if the forum exists?
|
||||
// TODO: Fix the races
|
||||
func (s *MemoryForumPermsStore) Get(fid, gid int) (fperms *ForumPerms, err error) {
|
||||
func (s *MemoryForumPermsStore) Get(fid, gid int) (fp *ForumPerms, err error) {
|
||||
var fmap map[int]*ForumPerms
|
||||
var ok bool
|
||||
if fid%2 == 0 {
|
||||
@ -206,22 +206,22 @@ func (s *MemoryForumPermsStore) Get(fid, gid int) (fperms *ForumPerms, err error
|
||||
s.oddLock.RUnlock()
|
||||
}
|
||||
if !ok {
|
||||
return fperms, ErrNoRows
|
||||
return fp, ErrNoRows
|
||||
}
|
||||
|
||||
fperms, ok = fmap[gid]
|
||||
fp, ok = fmap[gid]
|
||||
if !ok {
|
||||
return fperms, ErrNoRows
|
||||
return fp, ErrNoRows
|
||||
}
|
||||
return fperms, nil
|
||||
return fp, nil
|
||||
}
|
||||
|
||||
// TODO: Check if the forum exists?
|
||||
// TODO: Fix the races
|
||||
func (s *MemoryForumPermsStore) GetCopy(fid, gid int) (fperms ForumPerms, err error) {
|
||||
func (s *MemoryForumPermsStore) GetCopy(fid, gid int) (fp ForumPerms, err error) {
|
||||
fPermsPtr, err := s.Get(fid, gid)
|
||||
if err != nil {
|
||||
return fperms, err
|
||||
return fp, err
|
||||
}
|
||||
return *fPermsPtr, nil
|
||||
}
|
||||
|
@ -74,17 +74,17 @@ func InitPhrases(lang string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ext = filepath.Ext("/langs/" + path)
|
||||
ext := filepath.Ext("/langs/" + path)
|
||||
if ext != ".json" {
|
||||
log.Printf("Found a '%s' in /langs/", ext)
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var langPack LanguagePack
|
||||
err = json.Unmarshal(data, &langPack)
|
||||
if err != nil {
|
||||
@ -98,7 +98,7 @@ func InitPhrases(lang string) error {
|
||||
|
||||
// [prefix][name]phrase
|
||||
langPack.TmplPhrasesPrefixes = make(map[string]map[string]string)
|
||||
var conMap = make(map[string]string) // Cache phrase strings so we can de-dupe items to reduce memory use. There appear to be some minor improvements with this, although we would need a more thorough check to be sure.
|
||||
conMap := make(map[string]string) // Cache phrase strings so we can de-dupe items to reduce memory use. There appear to be some minor improvements with this, although we would need a more thorough check to be sure.
|
||||
for name, phrase := range langPack.TmplPhrases {
|
||||
_, ok := conMap[phrase]
|
||||
if !ok {
|
||||
@ -304,10 +304,10 @@ func GetTmplPhrasesByPrefix(prefix string) (phrases map[string]string, ok bool)
|
||||
return res, ok
|
||||
}
|
||||
|
||||
func getPlaceholder(prefix string, suffix string) string {
|
||||
func getPlaceholder(prefix, suffix string) string {
|
||||
return "{lang." + prefix + "[" + suffix + "]}"
|
||||
}
|
||||
func getPlaceholderBytes(prefix string, suffix string) []byte {
|
||||
func getPlaceholderBytes(prefix, suffix string) []byte {
|
||||
return []byte("{lang." + prefix + "[" + suffix + "]}")
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ type PollStore interface {
|
||||
Get(id int) (*Poll, error)
|
||||
Exists(id int) bool
|
||||
Create(parent Pollable, pollType int, pollOptions map[int]string) (int, error)
|
||||
CastVote(optionIndex int, pollID int, uid int, ip string) error
|
||||
CastVote(optionIndex, pollID, uid int, ip string) error
|
||||
Reload(id int) error
|
||||
//Count() int
|
||||
|
||||
@ -77,24 +77,24 @@ func (s *DefaultPollStore) Exists(id int) bool {
|
||||
}
|
||||
|
||||
func (s *DefaultPollStore) Get(id int) (*Poll, error) {
|
||||
poll, err := s.cache.Get(id)
|
||||
p, err := s.cache.Get(id)
|
||||
if err == nil {
|
||||
return poll, nil
|
||||
return p, nil
|
||||
}
|
||||
|
||||
poll = &Poll{ID: id}
|
||||
p = &Poll{ID: id}
|
||||
var optionTxt []byte
|
||||
err = s.get.QueryRow(id).Scan(&poll.ParentID, &poll.ParentTable, &poll.Type, &optionTxt, &poll.VoteCount)
|
||||
err = s.get.QueryRow(id).Scan(&p.ParentID, &p.ParentTable, &p.Type, &optionTxt, &p.VoteCount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(optionTxt, &poll.Options)
|
||||
err = json.Unmarshal(optionTxt, &p.Options)
|
||||
if err == nil {
|
||||
poll.QuickOptions = s.unpackOptionsMap(poll.Options)
|
||||
s.cache.Set(poll)
|
||||
p.QuickOptions = s.unpackOptionsMap(p.Options)
|
||||
s.cache.Set(p)
|
||||
}
|
||||
return poll, err
|
||||
return p, err
|
||||
}
|
||||
|
||||
// TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts?
|
||||
@ -212,9 +212,9 @@ func (s *DefaultPollStore) unpackOptionsMap(rawOptions map[int]string) []PollOpt
|
||||
}
|
||||
|
||||
// TODO: Use a transaction for this?
|
||||
func (s *DefaultPollStore) CastVote(optionIndex int, pollID int, uid int, ip string) error {
|
||||
func (s *DefaultPollStore) CastVote(optionIndex, pollID, uid int, ip string) error {
|
||||
if Config.DisablePollIP {
|
||||
ip = "0"
|
||||
ip = ""
|
||||
}
|
||||
_, err := s.addVote.Exec(pollID, uid, optionIndex, ip)
|
||||
if err != nil {
|
||||
|
@ -526,7 +526,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri
|
||||
|
||||
t := TItemHold(make(map[string]TItem))
|
||||
|
||||
topicsRow := &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "127.0.0.1", 1, 0, 1, 0, 1, "classname", 0, "", &user2, "", 0, &user3, "General", "/forum/general.2", nil}
|
||||
topicsRow := &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 0, 1, "classname", 0, "", &user2, "", 0, &user3, "General", "/forum/general.2", nil}
|
||||
t.AddStd("topics_topic", "c.TopicsRow", topicsRow)
|
||||
|
||||
poll := Poll{ID: 1, Type: 0, Options: map[int]string{0: "Nothing", 1: "Something"}, Results: map[int]int{0: 5, 1: 2}, QuickOptions: []PollOption{
|
||||
@ -535,7 +535,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri
|
||||
}, VoteCount: 7}
|
||||
avatar, microAvatar := BuildAvatar(62, "")
|
||||
miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}}
|
||||
topic := TopicUser{1, "blah", "Blah", "Hey there!", 62, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", 58, false, miniAttach, nil, false}
|
||||
topic := TopicUser{1, "blah", "Blah", "Hey there!", 62, false, false, now, now, 1, 1, 0, "", "::1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", 58, false, miniAttach, nil, false}
|
||||
var replyList []*ReplyUser
|
||||
// TODO: Do we really want the UID here to be zero?
|
||||
avatar, microAvatar = BuildAvatar(0, "")
|
||||
@ -816,6 +816,19 @@ func initDefaultTmplFuncMap() {
|
||||
return ""
|
||||
}
|
||||
|
||||
fmap["ptmpl"] = func(nameInt, pageInt, headerInt interface{}) interface{} {
|
||||
header := headerInt.(*Header)
|
||||
err := header.Theme.RunTmpl(nameInt.(string), pageInt, header.Writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
fmap["js"] = func() interface{} {
|
||||
return false
|
||||
}
|
||||
|
||||
fmap["flush"] = func() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
@ -114,6 +114,8 @@ func NewCTemplateSet(in string) *CTemplateSet {
|
||||
"reltime": true,
|
||||
"scope": true,
|
||||
"dyntmpl": true,
|
||||
"ptmpl": true,
|
||||
"js": true,
|
||||
"index": true,
|
||||
"flush": true,
|
||||
},
|
||||
@ -183,7 +185,7 @@ type OutFrag struct {
|
||||
Body string
|
||||
}
|
||||
|
||||
func (c *CTemplateSet) CompileByLoggedin(name string, fileDir string, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (stub string, gout string, mout string, err error) {
|
||||
func (c *CTemplateSet) CompileByLoggedin(name, fileDir, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (stub, gout, mout string, err error) {
|
||||
c.importMap = map[string]string{}
|
||||
for index, item := range c.baseImportMap {
|
||||
c.importMap[index] = item
|
||||
@ -233,15 +235,15 @@ import "errors"
|
||||
// TODO: Try to remove this redundant interface cast
|
||||
stub += `
|
||||
// nolint
|
||||
func Template_` + fname + `(tmpl_` + fname + `_i interface{}, w io.Writer) error {
|
||||
tmpl_` + fname + `_vars, ok := tmpl_` + fname + `_i.(` + expects + `)
|
||||
func Template_` + fname + `(tmpl_i interface{}, w io.Writer) error {
|
||||
tmpl_vars, ok := tmpl_i.(` + expects + `)
|
||||
if !ok {
|
||||
return errors.New("invalid page struct value")
|
||||
}
|
||||
if tmpl_` + fname + `_vars.CurrentUser.Loggedin {
|
||||
return Template_` + fname + `_member(tmpl_` + fname + `_i, w)
|
||||
if tmpl_vars.CurrentUser.Loggedin {
|
||||
return Template_` + fname + `_member(tmpl_i, w)
|
||||
}
|
||||
return Template_` + fname + `_guest(tmpl_` + fname + `_i, w)
|
||||
return Template_` + fname + `_guest(tmpl_i, w)
|
||||
}`
|
||||
|
||||
c.fileDir = fileDir
|
||||
@ -265,7 +267,7 @@ func Template_` + fname + `(tmpl_` + fname + `_i interface{}, w io.Writer) error
|
||||
return stub, gout, mout, err
|
||||
}
|
||||
|
||||
func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (out string, err error) {
|
||||
func (c *CTemplateSet) Compile(name, fileDir, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (out string, err error) {
|
||||
if c.config.Debug {
|
||||
c.logger.Println("Compiling template '" + name + "'")
|
||||
}
|
||||
@ -279,7 +281,7 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
|
||||
return c.compile(name, content, expects, expectsInt, varList, imports...)
|
||||
}
|
||||
|
||||
func (c *CTemplateSet) compile(name string, content string, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (out string, err error) {
|
||||
func (c *CTemplateSet) compile(name, content, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (out string, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println(r)
|
||||
@ -363,6 +365,7 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
|
||||
|
||||
var outBuf []OutBufferFrame
|
||||
rootHold := "tmpl_" + fname + "_vars"
|
||||
//rootHold := "tmpl_vars"
|
||||
con := CContext{
|
||||
RootHolder: rootHold,
|
||||
VarHolder: rootHold,
|
||||
@ -486,12 +489,17 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
|
||||
}
|
||||
|
||||
if c.lang == "normal" {
|
||||
fout += "// nolint\nfunc Template_" + fname + "(tmpl_" + fname + "_i interface{}, w io.Writer) error {\n"
|
||||
fout += `tmpl_` + fname + `_vars, ok := tmpl_` + fname + `_i.(` + expects + `)
|
||||
if !ok {
|
||||
return errors.New("invalid page struct value")
|
||||
}
|
||||
fout += "// nolint\nfunc Template_" + fname + "(tmpl_i interface{}, w io.Writer) error {\n"
|
||||
fout += `tmpl_` + fname + `_vars, ok := tmpl_i.(` + expects + `)
|
||||
if !ok {
|
||||
return errors.New("invalid page struct value")
|
||||
}
|
||||
`
|
||||
/*fout += `tmpl_vars, ok := tmpl_i.(` + expects + `)
|
||||
if !ok {
|
||||
return errors.New("invalid page struct value")
|
||||
}
|
||||
`*/
|
||||
fout += `var iw http.ResponseWriter
|
||||
gzw, ok := w.(c.GzipResponseWriter)
|
||||
if ok {
|
||||
@ -501,6 +509,7 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
|
||||
`
|
||||
} else {
|
||||
fout += "// nolint\nfunc Template_" + fname + "(tmpl_" + fname + "_vars interface{}, w io.Writer) error {\n"
|
||||
//fout += "// nolint\nfunc Template_" + fname + "(tmpl_vars interface{}, w io.Writer) error {\n"
|
||||
}
|
||||
|
||||
if len(c.langIndexToName) > 0 {
|
||||
@ -678,6 +687,15 @@ func (c *CTemplateSet) compileSwitch(con CContext, node parse.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
// simple constant folding
|
||||
if expr == "true" {
|
||||
c.compileSwitch(con, node.List)
|
||||
return
|
||||
} else if expr == "false" {
|
||||
c.compileSwitch(con, node.ElseList)
|
||||
return
|
||||
}
|
||||
|
||||
con.Push("startif", "if "+expr+" {\n")
|
||||
c.compileSwitch(con, node.List)
|
||||
if node.ElseList == nil {
|
||||
@ -980,16 +998,16 @@ func (c *CTemplateSet) compileExprSwitch(con CContext, node *parse.CommandNode)
|
||||
return out
|
||||
}
|
||||
|
||||
func (c *CTemplateSet) unknownNode(node parse.Node) {
|
||||
elem := reflect.ValueOf(node).Elem()
|
||||
func (c *CTemplateSet) unknownNode(n parse.Node) {
|
||||
elem := reflect.ValueOf(n).Elem()
|
||||
c.logger.Println("Unknown Kind:", elem.Kind())
|
||||
c.logger.Println("Unknown Type:", elem.Type().Name())
|
||||
panic("I don't know what node this is! Grr...")
|
||||
}
|
||||
|
||||
func (c *CTemplateSet) compileIdentSwitchN(con CContext, node *parse.CommandNode) (out string) {
|
||||
func (c *CTemplateSet) compileIdentSwitchN(con CContext, n *parse.CommandNode) (out string) {
|
||||
c.detail("in compileIdentSwitchN")
|
||||
out, _, _, _ = c.compileIdentSwitch(con, node)
|
||||
out, _, _, _ = c.compileIdentSwitch(con, n)
|
||||
return out
|
||||
}
|
||||
|
||||
@ -1052,7 +1070,7 @@ func (c *CTemplateSet) compareJoin(con CContext, pos int, node *parse.CommandNod
|
||||
return pos, out
|
||||
}
|
||||
|
||||
func (c *CTemplateSet) compileIdentSwitch(con CContext, node *parse.CommandNode) (out string, val reflect.Value, literal bool, notident bool) {
|
||||
func (c *CTemplateSet) compileIdentSwitch(con CContext, node *parse.CommandNode) (out string, val reflect.Value, literal, notident bool) {
|
||||
c.dumpCall("compileIdentSwitch", con, node)
|
||||
litString := func(inner string, bytes bool) {
|
||||
if !bytes {
|
||||
@ -1136,6 +1154,14 @@ ArgLoop:
|
||||
out = "c.HasWidgets(" + leftParam + "," + rightParam + ")"
|
||||
literal = true
|
||||
break ArgLoop
|
||||
case "js":
|
||||
if c.lang == "js" {
|
||||
out = "true"
|
||||
} else {
|
||||
out = "false"
|
||||
}
|
||||
literal = true
|
||||
break ArgLoop
|
||||
case "lang":
|
||||
// TODO: Implement string literals properly
|
||||
leftOp := node.Args[pos+1].String()
|
||||
@ -1172,7 +1198,7 @@ ArgLoop:
|
||||
for i := pos + 2; i < len(node.Args); i++ {
|
||||
op := node.Args[i].String()
|
||||
if op != "" {
|
||||
if /*op[0] == '.' || */op[0] == '$' {
|
||||
if /*op[0] == '.' || */ op[0] == '$' {
|
||||
panic("langf args cannot be dynamic")
|
||||
}
|
||||
if op[0] != '.' && op[0] != '"' && !unicode.IsDigit(rune(op[0])) {
|
||||
@ -1262,7 +1288,8 @@ ArgLoop:
|
||||
case "scope":
|
||||
literal = true
|
||||
break ArgLoop
|
||||
case "dyntmpl":
|
||||
// TODO: Optimise ptmpl
|
||||
case "dyntmpl", "ptmpl":
|
||||
var pageParam, headParam string
|
||||
// TODO: Implement string literals properly
|
||||
// TODO: Should we check to see if pos+3 is within the bounds of the slice?
|
||||
|
@ -16,8 +16,8 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
p "github.com/Azareal/Gosora/common/phrases"
|
||||
@ -91,7 +91,7 @@ type ThemeMapTmplToDock struct {
|
||||
func (t *Theme) LoadStaticFiles() error {
|
||||
t.ResourceTemplates = template.New("")
|
||||
fmap := make(map[string]interface{})
|
||||
fmap["lang"] = func(phraseNameInt interface{}, tmplInt interface{}) interface{} {
|
||||
fmap["lang"] = func(phraseNameInt, tmplInt interface{}) interface{} {
|
||||
phraseName, ok := phraseNameInt.(string)
|
||||
if !ok {
|
||||
panic("phraseNameInt is not a string")
|
||||
@ -167,7 +167,7 @@ func (t *Theme) AddThemeStaticFiles() error {
|
||||
hasher.Write(data)
|
||||
checksum := hex.EncodeToString(hasher.Sum(nil))
|
||||
|
||||
StaticFiles.Set("/s/"+t.Name+path, SFile{data, gzipData, checksum,t.Name+path + "?h=" + checksum, 0, int64(len(data)), int64(len(gzipData)),strconv.Itoa(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||
StaticFiles.Set("/s/"+t.Name+path, SFile{data, gzipData, checksum, t.Name + path + "?h=" + checksum, 0, int64(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||
|
||||
DebugLog("Added the '/" + t.Name + path + "' static file for theme " + t.Name + ".")
|
||||
return nil
|
||||
@ -252,7 +252,6 @@ func UpdateDefaultTheme(t *Theme) error {
|
||||
if !ok {
|
||||
return ErrNoDefaultTheme
|
||||
}
|
||||
|
||||
err = dtheme.setActive(false)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -236,7 +236,7 @@ var imageExts = ["png", "jpg", "jpe","jpeg","jif","jfi","jfif", "svg", "bmp", "g
|
||||
});
|
||||
|
||||
let bulkActionSender = function(action, selectedTopics, fragBit) {
|
||||
let url = "/topic/"+action+"/submit/"+fragBit+"?s=" + me.User.S;
|
||||
let url = "/topic/"+action+"/submit/"+fragBit+"?s="+me.User.S;
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "POST",
|
||||
@ -265,7 +265,7 @@ var imageExts = ["png", "jpg", "jpe","jpeg","jif","jfi","jfif", "svg", "bmp", "g
|
||||
let fid = this.getAttribute("data-fid");
|
||||
if (fid == null) return;
|
||||
this.classList.add("pane_selected");
|
||||
console.log("fid: " + fid);
|
||||
console.log("fid:" + fid);
|
||||
forumToMoveTo = fid;
|
||||
|
||||
$("#mover_submit").unbind("click");
|
||||
@ -298,8 +298,8 @@ var imageExts = ["png", "jpg", "jpe","jpeg","jif","jfi","jfif", "svg", "bmp", "g
|
||||
}
|
||||
|
||||
var pollInputIndex = 1;
|
||||
$("#add_poll_button").click((event) => {
|
||||
event.preventDefault();
|
||||
$("#add_poll_button").click((ev) => {
|
||||
ev.preventDefault();
|
||||
$(".poll_content_row").removeClass("auto_hide");
|
||||
$("#has_poll_input").val("1");
|
||||
$(".pollinputinput").click(addPollInput);
|
||||
|
@ -1,13 +1,13 @@
|
||||
(() => {
|
||||
addInitHook("end_init", () => {
|
||||
fetch("/api/watches/")
|
||||
.then(response => {
|
||||
if(response.status!==200) {
|
||||
.then(resp => {
|
||||
if(resp.status!==200) {
|
||||
console.log("error");
|
||||
console.log("response:", response);
|
||||
console.log("response:", resp);
|
||||
return;
|
||||
}
|
||||
response.text().then(data => eval(data));
|
||||
resp.text().then(data => eval(data));
|
||||
})
|
||||
.catch(err => console.log("err:", err));
|
||||
});
|
||||
|
@ -43,7 +43,7 @@ func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, hea
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildBasePage(w http.ResponseWriter, r *http.Request, user *c.User, titlePhrase string, zone string) (*c.BasePanelPage, c.RouteError) {
|
||||
func buildBasePage(w http.ResponseWriter, r *http.Request, user *c.User, titlePhrase, zone string) (*c.BasePanelPage, c.RouteError) {
|
||||
header, stats, ferr := c.PanelUserCheck(w, r, user)
|
||||
if ferr != nil {
|
||||
return nil, ferr
|
||||
|
@ -214,19 +214,19 @@ func GroupsPromotionsCreateSubmit(w http.ResponseWriter, r *http.Request, user c
|
||||
return c.LocalError("posts must be integer", w, r, user)
|
||||
}
|
||||
|
||||
registeredHours, err := strconv.Atoi(r.FormValue("registered_hours"))
|
||||
regHours, err := strconv.Atoi(r.FormValue("registered_hours"))
|
||||
if err != nil {
|
||||
return c.LocalError("registered_hours must be integer", w, r, user)
|
||||
}
|
||||
registeredDays, err := strconv.Atoi(r.FormValue("registered_days"))
|
||||
regDays, err := strconv.Atoi(r.FormValue("registered_days"))
|
||||
if err != nil {
|
||||
return c.LocalError("registered_days must be integer", w, r, user)
|
||||
}
|
||||
registeredMonths, err := strconv.Atoi(r.FormValue("registered_months"))
|
||||
regMonths, err := strconv.Atoi(r.FormValue("registered_months"))
|
||||
if err != nil {
|
||||
return c.LocalError("registered_months must be integer", w, r, user)
|
||||
}
|
||||
registeredMinutes := (registeredHours * 60) + (registeredDays * 24 * 60) + (registeredMonths * 30 * 24 * 60)
|
||||
regMinutes := (regHours * 60) + (regDays * 24 * 60) + (regMonths * 30 * 24 * 60)
|
||||
|
||||
g, err := c.Groups.Get(from)
|
||||
ferr := groupCheck(w, r, user, g, err)
|
||||
@ -238,7 +238,7 @@ func GroupsPromotionsCreateSubmit(w http.ResponseWriter, r *http.Request, user c
|
||||
if err != nil {
|
||||
return ferr
|
||||
}
|
||||
pid, err := c.GroupPromotions.Create(from, to, twoWay, level, posts, registeredMinutes)
|
||||
pid, err := c.GroupPromotions.Create(from, to, twoWay, level, posts, regMinutes)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ func LogsRegs(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
|
||||
logCount := c.RegLogs.Count()
|
||||
page, _ := strconv.Atoi(r.FormValue("page"))
|
||||
perPage := 12
|
||||
@ -174,7 +173,6 @@ func LogsMod(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
|
||||
page, _ := strconv.Atoi(r.FormValue("page"))
|
||||
perPage := 12
|
||||
offset, page, lastPage := c.PageOffset(c.ModLogs.Count(), page, perPage)
|
||||
|
@ -27,7 +27,7 @@ func init() {
|
||||
replyStmts = ReplyStmts{
|
||||
// TODO: Less race-y attachment count updates
|
||||
updateAttachs: acc.Update("replies").Set("attachCount=?").Where("rid=?").Prepare(),
|
||||
createReplyPaging: acc.Select("replies").Cols("rid").Where("rid >= ? - 1 AND tid = ?").Orderby("rid ASC").Prepare(),
|
||||
createReplyPaging: acc.Select("replies").Cols("rid").Where("rid >= ? - 1 AND tid=?").Orderby("rid ASC").Prepare(),
|
||||
}
|
||||
return acc.FirstError()
|
||||
})
|
||||
|
@ -117,7 +117,6 @@ func UnbanUser(w http.ResponseWriter, r *http.Request, user c.User, suid string)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
if !targetUser.IsBanned {
|
||||
return c.LocalError("The user you're trying to unban isn't banned.", w, r, user)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
{{if gt .Page 1}}<div id="prevFloat" class="prev_button"><a class="prev_link" aria-label="{{lang "paginator.prev_page_aria"}}" rel="prev" href="{{.Forum.Link}}?page={{subtract .Page 1}}">{{lang "paginator.less_than"}}</a></div>{{end}}
|
||||
{{if ne .LastPage .Page}}<div id="nextFloat" class="next_button"><a class="next_link" aria-label="{{lang "paginator.next_page_aria"}}" rel="next" href="{{.Forum.Link}}?page={{add .Page 1}}">{{lang "paginator.greater_than"}}</a></div>{{end}}
|
||||
<link rel="canonical" href="//{{.Site.URL}}{{.Forum.Link}}{{if gt .Page 1}}?page={{.Page}}{{end}}" />
|
||||
<link rel="canonical" href="//{{.Site.URL}}{{.Forum.Link}}{{if gt .Page 1}}?page={{.Page}}{{end}}"/>
|
||||
|
||||
<main id="forumItemList" itemscope itemtype="http://schema.org/ItemList">
|
||||
<div id="forum_head_block" class="rowblock rowhead topic_list_title_block{{if .CurrentUser.Loggedin}} has_opt{{end}}">
|
||||
@ -49,7 +49,7 @@
|
||||
{{range .ItemList}}<div class="topic_row{{if .Sticky}} topic_sticky{{else if .IsClosed}} topic_closed{{end}}" data-tid="{{.ID}}">
|
||||
<div class="rowitem topic_left passive datarow">
|
||||
<span class="selector"></span>
|
||||
<a href="{{.Creator.Link}}"><img src="{{.Creator.MicroAvatar}}" height=64 alt="Avatar" title="{{.Creator.Name}}'s Avatar" aria-hidden="true" /></a>
|
||||
<a href="{{.Creator.Link}}"><img src="{{.Creator.MicroAvatar}}" height=64 alt="Avatar" title="{{.Creator.Name}}'s Avatar" aria-hidden="true"/></a>
|
||||
<span class="topic_inner_left">
|
||||
<a class="rowtopic" href="{{.Link}}" itemprop="itemListElement" title="{{.Title}}"><span>{{.Title}}</span></a>
|
||||
<br /><a class="rowsmall starter" href="{{.Creator.Link}}" title="{{.Creator.Name}}">{{.Creator.Name}}</a>
|
||||
@ -72,7 +72,7 @@
|
||||
</div>
|
||||
<div class="rowitem topic_right passive datarow">
|
||||
<div class="topic_right_inside">
|
||||
<a href="{{.LastUser.Link}}"><img src="{{.LastUser.MicroAvatar}}" height=64 alt="Avatar" title="{{.LastUser.Name}}'s Avatar" aria-hidden="true" /></a>
|
||||
<a href="{{.LastUser.Link}}"><img src="{{.LastUser.MicroAvatar}}" height=64 alt="Avatar" title="{{.LastUser.Name}}'s Avatar" aria-hidden="true"/></a>
|
||||
<span>
|
||||
<a href="{{.LastUser.Link}}" class="lastName" title="{{.LastUser.Name}}">{{.LastUser.Name}}</a><br>
|
||||
<a href="{{.Link}}?page={{.LastPage}}{{if .LastReplyID}}#post-{{.LastReplyID}}{{end}}" class="rowsmall lastReplyAt" title="{{abstime .LastReplyAt}}">{{reltime .LastReplyAt}}</a>
|
||||
|
@ -1,5 +1,5 @@
|
||||
{{range .ItemList}}<article {{scope "post"}} id="post-{{.ID}}" itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item{{if .ActionType}} action_item{{end}}{{if .Attachments}} has_attachs{{end}}">
|
||||
{{template "topic_alt_userinfo.html" . }}
|
||||
{{if js}}js{{/**{{ptmpl "topic_alt_userinfo" .}}**/}}{{else}}{{template "topic_alt_userinfo.html" . }}{{end}}
|
||||
<div class="content_container">
|
||||
{{if .ActionType}}
|
||||
<span class="action_icon" aria-hidden="true">{{.ActionIcon}}</span>
|
||||
@ -14,7 +14,7 @@
|
||||
{{range .Attachments}}
|
||||
<div class="attach_item attach_item_item{{if .Image}} attach_image_holder{{end}}">
|
||||
{{if .Image}}<img src="//{{$.Header.Site.URL}}/attachs/{{.Path}}?sid={{.SectionID}}&stype=forums" height=24 width=24 />{{end}}
|
||||
<span class="attach_item_path" aid="{{.ID}}" fullPath="//{{$.Header.Site.URL}}/attachs/{{.Path}}">{{.Path}}</span>
|
||||
<span class="attach_item_path" aid={{.ID}} fullPath="//{{$.Header.Site.URL}}/attachs/{{.Path}}">{{.Path}}</span>
|
||||
<button class="attach_item_select">{{lang "topic.select_button_text"}}</button>
|
||||
<button class="attach_item_copy">{{lang "topic.copy_button_text"}}</button>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user