diff --git a/common/menus.go b/common/menus.go index 78805511..9faafbf6 100644 --- a/common/menus.go +++ b/common/menus.go @@ -7,6 +7,7 @@ import ( "io" "io/ioutil" "strconv" + "strings" "../query_gen/lib" ) @@ -19,9 +20,15 @@ type MenuListHolder struct { Variations map[int]menuTmpl // 0 = Guest Menu, 1 = Member Menu, 2 = Super Mod Menu, 3 = Admin Menu } +type menuPath struct { + Path string + Index int +} + type menuTmpl struct { RenderBuffer [][]byte VariableIndices []int + PathMappings []menuPath } type MenuItem struct { @@ -135,11 +142,8 @@ func (hold *MenuListHolder) Preparse() error { } var addVariation = func(index int, callback func(mitem MenuItem) bool) { - renderBuffer, variableIndices := hold.Scan(tmpls, callback) - hold.Variations[index] = menuTmpl{renderBuffer, variableIndices} - //fmt.Print("renderBuffer: ") - //menuDumpSlice(renderBuffer) - //fmt.Printf("\nvariableIndices: %+v\n", variableIndices) + renderBuffer, variableIndices, pathList := hold.Scan(tmpls, callback) + hold.Variations[index] = menuTmpl{renderBuffer, variableIndices, pathList} } // Guest Menu @@ -202,15 +206,11 @@ func skipUntilCharsExist(tmplData []byte, i int, expects []byte) (newI int, hasI func skipAllUntilCharsExist(tmplData []byte, i int, expects []byte) (newI int, hasIt bool) { j := i expectIndex := 0 - //fmt.Printf("tmplData: %+v\n", string(tmplData)) for ; j < len(tmplData) && expectIndex < len(expects); j++ { - //fmt.Println("j: ", j) - //fmt.Println("tmplData[j]: ", string(tmplData[j])+" ") if tmplData[j] == expects[expectIndex] { //fmt.Printf("expects[expectIndex]: %+v - %d\n", string(expects[expectIndex]), expectIndex) expectIndex++ if len(expects) <= expectIndex { - //fmt.Println("breaking") break } } else { @@ -226,8 +226,6 @@ func skipAllUntilCharsExist(tmplData []byte, i int, expects []byte) (newI int, h expectIndex = 0 } } - //fmt.Println("len(expects): ", len(expects)) - //fmt.Println("expectIndex: ", expectIndex) return j, len(expects) == expectIndex } @@ -254,19 +252,16 @@ func menuDumpSlice(outerSlice [][]byte) { } func (hold *MenuListHolder) Parse(name string, tmplData []byte) (menuTmpl MenuTmpl) { - //fmt.Println("tmplData: ", string(tmplData)) var textBuffer, variableBuffer [][]byte var renderList []menuRenderItem var subBuffer []byte // ? We only support simple properties on MenuItem right now var addVariable = func(name []byte) { - //fmt.Println("appending subBuffer: ", string(subBuffer)) // TODO: Check if the subBuffer has any items or is empty textBuffer = append(textBuffer, subBuffer) subBuffer = nil - //fmt.Println("adding variable: ", string(name)) variableBuffer = append(variableBuffer, name) renderList = append(renderList, menuRenderItem{0, len(textBuffer) - 1}) renderList = append(renderList, menuRenderItem{1, len(variableBuffer) - 1}) @@ -277,10 +272,8 @@ func (hold *MenuListHolder) Parse(name string, tmplData []byte) (menuTmpl MenuTm for i := 0; i < len(tmplData); i++ { char := tmplData[i] if char == '{' { - //fmt.Println("found open fence") dotIndex, hasDot := skipUntilIfExists(tmplData, i, '.') if !hasDot { - //fmt.Println("no dot, assumed template function style") // Template function style langIndex, hasChars := skipUntilCharsExist(tmplData, i+1, []byte("lang")) if hasChars { @@ -302,7 +295,6 @@ func (hold *MenuListHolder) Parse(name string, tmplData []byte) (menuTmpl MenuTm } fenceIndex, hasFence := skipUntilIfExists(tmplData, dotIndex, '}') if !hasFence { - //fmt.Println("no end fence") break } addVariable(tmplData[dotIndex:fenceIndex]) @@ -317,25 +309,21 @@ func (hold *MenuListHolder) Parse(name string, tmplData []byte) (menuTmpl MenuTm renderList = append(renderList, menuRenderItem{0, len(textBuffer) - 1}) } - //fmt.Println("name: ", name) - //fmt.Print("textBuffer: ") - //menuDumpSlice(textBuffer) - //fmt.Print("\nvariableBuffer: ") - //menuDumpSlice(variableBuffer) - //fmt.Printf("\nrenderList: %+v\n", renderList) return MenuTmpl{name, textBuffer, variableBuffer, renderList} } -func (hold *MenuListHolder) Scan(menuTmpls map[string]MenuTmpl, showItem func(mitem MenuItem) bool) (renderBuffer [][]byte, variableIndices []int) { +func (hold *MenuListHolder) Scan(menuTmpls map[string]MenuTmpl, showItem func(mitem MenuItem) bool) (renderBuffer [][]byte, variableIndices []int, pathList []menuPath) { for _, mitem := range hold.List { // Do we want this item in this variation of the menu? if !showItem(mitem) { continue } renderBuffer, variableIndices = hold.ScanItem(menuTmpls, mitem, renderBuffer, variableIndices) + pathList = append(pathList, menuPath{mitem.Path, len(renderBuffer) - 1}) } + // TODO: Need more coalescing in the renderBuffer - return renderBuffer, variableIndices + return renderBuffer, variableIndices, pathList } // Note: This doesn't do a visibility check like hold.Scan() does @@ -345,7 +333,6 @@ func (hold *MenuListHolder) ScanItem(menuTmpls map[string]MenuTmpl, mitem MenuIt menuTmpl = menuTmpls["menu_item"] } - //fmt.Println("menuTmpl: ", menuTmpl) for _, renderItem := range menuTmpl.RenderList { if renderItem.Type == 0 { renderBuffer = append(renderBuffer, menuTmpl.TextBuffer[renderItem.Index]) @@ -353,72 +340,70 @@ func (hold *MenuListHolder) ScanItem(menuTmpls map[string]MenuTmpl, mitem MenuIt } variable := menuTmpl.VariableBuffer[renderItem.Index] - //fmt.Println("initial variable: ", string(variable)) dotAt, hasDot := skipUntilIfExists(variable, 0, '.') if !hasDot { - //fmt.Println("no dot") continue } if bytes.Equal(variable[:dotAt], []byte("lang")) { - //fmt.Println("lang: ", string(bytes.TrimPrefix(variable[dotAt:], []byte(".")))) renderBuffer = append(renderBuffer, []byte(GetTmplPhrase(string(bytes.TrimPrefix(variable[dotAt:], []byte(".")))))) - } else { - var renderItem []byte - switch string(variable) { - case ".ID": - renderItem = []byte(strconv.Itoa(mitem.ID)) - case ".Name": - renderItem = []byte(mitem.Name) - case ".HTMLID": - renderItem = []byte(mitem.HTMLID) - case ".CSSClass": - renderItem = []byte(mitem.CSSClass) - case ".Position": - renderItem = []byte(mitem.Position) - case ".Path": - renderItem = []byte(mitem.Path) - case ".Aria": - renderItem = []byte(mitem.Aria) - case ".Tooltip": - renderItem = []byte(mitem.Tooltip) - } + continue + } - _, hasInnerVar := skipUntilIfExists(renderItem, 0, '{') - if hasInnerVar { - //fmt.Println("inner var: ", string(renderItem)) - dotAt, hasDot := skipUntilIfExists(renderItem, 0, '.') - endFence, hasEndFence := skipUntilIfExists(renderItem, dotAt, '}') - if !hasDot || !hasEndFence || (endFence-dotAt) <= 1 { - renderBuffer = append(renderBuffer, renderItem) - variableIndices = append(variableIndices, len(renderBuffer)-1) - continue - } + var renderItem []byte + switch string(variable) { + case ".ID": + renderItem = []byte(strconv.Itoa(mitem.ID)) + case ".Name": + renderItem = []byte(mitem.Name) + case ".HTMLID": + renderItem = []byte(mitem.HTMLID) + case ".CSSClass": + renderItem = []byte(mitem.CSSClass) + case ".Position": + renderItem = []byte(mitem.Position) + case ".Path": + renderItem = []byte(mitem.Path) + case ".Aria": + renderItem = []byte(mitem.Aria) + case ".Tooltip": + renderItem = []byte(mitem.Tooltip) + case ".CSSActive": + renderItem = []byte("{dyn.active}") + } - if bytes.Equal(renderItem[1:dotAt], []byte("lang")) { - //fmt.Println("lang var: ", string(renderItem[dotAt+1:endFence])) - renderBuffer = append(renderBuffer, []byte(GetTmplPhrase(string(renderItem[dotAt+1:endFence])))) - } else { - //fmt.Println("other var: ", string(variable[:dotAt])) - if len(renderItem) > 0 { - renderBuffer = append(renderBuffer, renderItem) - variableIndices = append(variableIndices, len(renderBuffer)-1) - } - } + _, hasInnerVar := skipUntilIfExists(renderItem, 0, '{') + if hasInnerVar { + fmt.Println("inner var: ", string(renderItem)) + dotAt, hasDot := skipUntilIfExists(renderItem, 0, '.') + endFence, hasEndFence := skipUntilIfExists(renderItem, dotAt, '}') + if !hasDot || !hasEndFence || (endFence-dotAt) <= 1 { + renderBuffer = append(renderBuffer, renderItem) + variableIndices = append(variableIndices, len(renderBuffer)-1) continue } - //fmt.Println("normal var: ", string(variable[:dotAt])) - if len(renderItem) > 0 { - renderBuffer = append(renderBuffer, renderItem) + if bytes.Equal(renderItem[1:dotAt], []byte("lang")) { + //fmt.Println("lang var: ", string(renderItem[dotAt+1:endFence])) + renderBuffer = append(renderBuffer, []byte(GetTmplPhrase(string(renderItem[dotAt+1:endFence])))) + } else { + fmt.Println("other var: ", string(variable[:dotAt])) + if len(renderItem) > 0 { + renderBuffer = append(renderBuffer, renderItem) + variableIndices = append(variableIndices, len(renderBuffer)-1) + } } + continue + } + if len(renderItem) > 0 { + renderBuffer = append(renderBuffer, renderItem) } } return renderBuffer, variableIndices } // TODO: Pre-render the lang stuff -func (hold *MenuListHolder) Build(w io.Writer, user *User) error { +func (hold *MenuListHolder) Build(w io.Writer, user *User, pathPrefix string) error { var mTmpl menuTmpl if !user.Loggedin { mTmpl = hold.Variations[0] @@ -429,11 +414,12 @@ func (hold *MenuListHolder) Build(w io.Writer, user *User) error { } else { mTmpl = hold.Variations[1] } + if pathPrefix == "" { + pathPrefix = Config.DefaultPath + } if len(mTmpl.VariableIndices) == 0 { - //fmt.Println("no variable indices") for _, renderItem := range mTmpl.RenderBuffer { - //fmt.Printf("renderItem: %+v\n", renderItem) w.Write(renderItem) } return nil @@ -442,17 +428,15 @@ func (hold *MenuListHolder) Build(w io.Writer, user *User) error { var nearIndex = 0 for index, renderItem := range mTmpl.RenderBuffer { if index != mTmpl.VariableIndices[nearIndex] { - //fmt.Println("wrote text: ", string(renderItem)) w.Write(renderItem) continue } - - //fmt.Println("variable: ", string(renderItem)) variable := renderItem // ? - I can probably remove this check now that I've kicked it upstream, or we could keep it here for safety's sake? if len(variable) == 0 { continue } + prevIndex := 0 for i := 0; i < len(renderItem); i++ { fenceStart, hasFence := skipUntilIfExists(variable, i, '{') @@ -469,9 +453,9 @@ func (hold *MenuListHolder) Build(w io.Writer, user *User) error { if !hasDot { continue } - //fmt.Println("checking me: ", string(variable[fenceStart+1:dotAt])) - if bytes.Equal(variable[fenceStart+1:dotAt], []byte("me")) { - //fmt.Println("maybe me variable") + + switch string(variable[fenceStart+1 : dotAt]) { + case "me": w.Write(variable[prevIndex:fenceStart]) switch string(variable[dotAt+1 : fenceEnd]) { case "Link": @@ -479,11 +463,32 @@ func (hold *MenuListHolder) Build(w io.Writer, user *User) error { case "Session": w.Write([]byte(user.Session)) } + prevIndex = fenceEnd + // TODO: Optimise this + case "dyn": + w.Write(variable[prevIndex:fenceStart]) + var pmi int + for ii, pathItem := range mTmpl.PathMappings { + pmi = ii + if pathItem.Index > index { + break + } + } + + if len(mTmpl.PathMappings) != 0 { + path := mTmpl.PathMappings[pmi].Path + if path == "" || path == "/" { + path = Config.DefaultPath + } + if strings.HasPrefix(path, pathPrefix) { + w.Write([]byte(" menu_active")) + } + } + prevIndex = fenceEnd } } - //fmt.Println("prevIndex: ", prevIndex) - //fmt.Println("len(variable)-1: ", len(variable)-1) + w.Write(variable[prevIndex : len(variable)-1]) if len(mTmpl.VariableIndices) > (nearIndex + 1) { nearIndex++ diff --git a/common/pages.go b/common/pages.go index c68089ef..df635320 100644 --- a/common/pages.go +++ b/common/pages.go @@ -24,6 +24,7 @@ type Header struct { //TemplateName string // TODO: Use this to move template calls to the router rather than duplicating them over and over and over? CurrentUser User // TODO: Deprecate CurrentUser on the page structs and use a pointer here Zone string + Path string MetaDesc string Writer http.ResponseWriter ExtData ExtData @@ -158,6 +159,7 @@ type AccountDashPage struct { CurrentScore int NextScore int NextLevel int + Percentage int } type LevelListItem struct { diff --git a/common/phrases.go b/common/phrases.go index 8bd245e6..6f8d02ec 100644 --- a/common/phrases.go +++ b/common/phrases.go @@ -239,6 +239,14 @@ func GetTitlePhrase(name string) string { return res } +func GetTitlePhrasef(name string, params ...interface{}) string { + res, ok := currentLangPack.Load().(*LanguagePack).PageTitles[name] + if !ok { + return getPhrasePlaceholder("title", name) + } + return fmt.Sprintf(res, params...) +} + func GetTmplPhrase(name string) string { res, ok := currentLangPack.Load().(*LanguagePack).TmplPhrases[name] if !ok { diff --git a/common/widgets.go b/common/widgets.go index b69b9f8e..88af497b 100644 --- a/common/widgets.go +++ b/common/widgets.go @@ -136,7 +136,7 @@ func BuildWidget(dock string, header *Header) (sbody string) { // 1 = id for the default menu mhold, err := Menus.Get(1) if err == nil { - err := mhold.Build(header.Writer, &header.CurrentUser) + err := mhold.Build(header.Writer, &header.CurrentUser, header.Path) if err != nil { LogError(err) } diff --git a/main.go b/main.go index 7e8451ff..57cd229f 100644 --- a/main.go +++ b/main.go @@ -93,7 +93,7 @@ func afterDBInit() (err error) { } fmt.Printf("menuHold: %+v\n", menuHold) var b bytes.Buffer - menuHold.Build(&b, &common.GuestUser) + menuHold.Build(&b, &common.GuestUser, "/") fmt.Println("menuHold output: ", string(b.Bytes())) log.Print("Initialising the authentication system") diff --git a/routes/account.go b/routes/account.go index 848443ce..b63198d3 100644 --- a/routes/account.go +++ b/routes/account.go @@ -362,6 +362,7 @@ func accountEditHead(titlePhrase string, w http.ResponseWriter, r *http.Request, return nil, ferr } header.Title = common.GetTitlePhrase(titlePhrase) + header.Path = "/user/edit/" header.AddSheet(header.Theme.Name + "/account.css") header.AddScript("account.js") return header, nil @@ -394,8 +395,9 @@ func AccountEdit(w http.ResponseWriter, r *http.Request, user common.User) commo prevScore := common.GetLevelScore(user.Level) currentScore := user.Score - prevScore nextScore := common.GetLevelScore(user.Level+1) - prevScore + perc := int(math.Ceil((float64(nextScore) / float64(currentScore)) * 100)) - pi := common.AccountDashPage{header, mfaSetup, currentScore, nextScore, user.Level + 1} + pi := common.AccountDashPage{header, mfaSetup, currentScore, nextScore, user.Level + 1, perc * 2} if common.RunPreRenderHook("pre_render_account_own_edit", w, r, &user, &pi) { return nil } diff --git a/routes/forum_list.go b/routes/forum_list.go index 4970c3d2..051564f1 100644 --- a/routes/forum_list.go +++ b/routes/forum_list.go @@ -14,6 +14,7 @@ func ForumList(w http.ResponseWriter, r *http.Request, user common.User) common. } header.Title = common.GetTitlePhrase("forums") header.Zone = "forums" + header.Path = "/forums/" header.MetaDesc = header.Settings["meta_desc"].(string) var err error diff --git a/routes/profile.go b/routes/profile.go index 78699525..04b23bb9 100644 --- a/routes/profile.go +++ b/routes/profile.go @@ -27,6 +27,7 @@ func init() { }) } +// TODO: Remove the View part of the name? func ViewProfile(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { header, ferr := common.UserCheck(w, r, &user) if ferr != nil { @@ -68,6 +69,7 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user common.User) commo } // TODO: Add a phrase for this title header.Title = puser.Name + "'s Profile" + header.Path = common.BuildProfileURL(common.NameToSlug(puser.Name), puser.ID) // Get the replies.. rows, err := profileStmts.getReplies.Query(puser.ID) diff --git a/routes/topic.go b/routes/topic.go index 97c7acc5..31990bf6 100644 --- a/routes/topic.go +++ b/routes/topic.go @@ -59,18 +59,17 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit return common.InternalError(err, w, r) } topic.ClassName = "" - //log.Printf("topic: %+v\n", topic) header, ferr := common.ForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic { - //log.Printf("user.Perms: %+v\n", user.Perms) return common.NoPermissions(w, r, user) } header.Title = topic.Title header.Zone = "view_topic" + header.Path = common.BuildTopicURL(common.NameToSlug(topic.Title), topic.ID) topic.ContentHTML = common.ParseMessage(topic.Content, topic.ParentID, "forums") topic.ContentLines = strings.Count(topic.Content, "\n") diff --git a/routes/topic_list.go b/routes/topic_list.go index a1f1c721..68532f1e 100644 --- a/routes/topic_list.go +++ b/routes/topic_list.go @@ -15,6 +15,7 @@ func TopicList(w http.ResponseWriter, r *http.Request, user common.User) common. } header.Title = common.GetTitlePhrase("topics") header.Zone = "topics" + header.Path = "/topics/" header.MetaDesc = header.Settings["meta_desc"].(string) group, err := common.Groups.Get(user.Group) @@ -62,6 +63,7 @@ func TopicListMostViewed(w http.ResponseWriter, r *http.Request, user common.Use } header.Title = common.GetTitlePhrase("topics") header.Zone = "topics" + header.Path = "/topics/" header.MetaDesc = header.Settings["meta_desc"].(string) group, err := common.Groups.Get(user.Group) diff --git a/templates/account_own_edit.html b/templates/account_own_edit.html index e4577e02..0961f254 100644 --- a/templates/account_own_edit.html +++ b/templates/account_own_edit.html @@ -21,14 +21,11 @@