From a1a90ab9fdca36010655fb0bd8908e70d2e17f20 Mon Sep 17 00:00:00 2001 From: Azareal Date: Fri, 28 Dec 2018 21:13:06 +1000 Subject: [PATCH] The opening posts should be properly rendered after inline edits now. Switched out the / in the headers for a - The template generator can now handle FieldNodes passed to templates. Added the topic_alt_userinfo template. Added the topic_alt_quick_reply template. --- common/templates/templates.go | 121 +++++++++++++++++++-------- public/global.js | 10 ++- routes/topic.go | 14 +++- templates/topic_alt.html | 49 +---------- templates/topic_alt_posts.html | 8 +- templates/topic_alt_quick_reply.html | 38 +++++++++ templates/topic_alt_userinfo.html | 7 ++ templates/topics.html | 2 +- 8 files changed, 156 insertions(+), 93 deletions(-) create mode 100644 templates/topic_alt_quick_reply.html create mode 100644 templates/topic_alt_userinfo.html diff --git a/common/templates/templates.go b/common/templates/templates.go index f528801d..f856daaa 100644 --- a/common/templates/templates.go +++ b/common/templates/templates.go @@ -612,10 +612,40 @@ func (c *CTemplateSet) compileRangeNode(con CContext, node *parse.RangeNode) { } } +// ! Temporary, we probably want something that is good with non-struct pointers too +// For compileSubSwitch and compileSubTemplate +func (c *CTemplateSet) skipStructPointers(cur reflect.Value, id string) reflect.Value { + if cur.Kind() == reflect.Ptr { + c.detail("Looping over pointer") + for cur.Kind() == reflect.Ptr { + cur = cur.Elem() + } + c.detail("Data Kind:", cur.Kind().String()) + c.detail("Field Bit:", id) + } + return cur +} + +// For compileSubSwitch and compileSubTemplate +func (c *CTemplateSet) checkIfValid(cur reflect.Value, varHolder string, holdreflect reflect.Value, varBit string, multiline bool) { + if !cur.IsValid() { + c.critical("Debug Data:") + c.critical("Holdreflect:", holdreflect) + c.critical("Holdreflect.Kind():", holdreflect.Kind()) + if !c.config.SuperDebug { + c.critical("cur.Kind():", cur.Kind().String()) + } + c.critical("") + if !multiline { + panic(varHolder + varBit + "^\n" + "Invalid value. Maybe, it doesn't exist?") + } + panic(varBit + "^\n" + "Invalid value. Maybe, it doesn't exist?") + } +} + func (c *CTemplateSet) compileSubSwitch(con CContext, node *parse.CommandNode) { c.dumpCall("compileSubSwitch", con, node) - firstWord := node.Args[0] - switch n := firstWord.(type) { + switch n := node.Args[0].(type) { case *parse.FieldNode: c.detail("Field Node:", n.Ident) /* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Variable declarations are coming soon! */ @@ -627,45 +657,19 @@ func (c *CTemplateSet) compileSubSwitch(con CContext, node *parse.CommandNode) { varBit += ".(" + cur.Type().Name() + ")" } - // ! Might not work so well for non-struct pointers - skipPointers := func(cur reflect.Value, id string) reflect.Value { - if cur.Kind() == reflect.Ptr { - c.detail("Looping over pointer") - for cur.Kind() == reflect.Ptr { - cur = cur.Elem() - } - c.detail("Data Kind:", cur.Kind().String()) - c.detail("Field Bit:", id) - } - return cur - } - var assLines string var multiline = false for _, id := range n.Ident { c.detail("Data Kind:", cur.Kind().String()) c.detail("Field Bit:", id) - cur = skipPointers(cur, id) - - if !cur.IsValid() { - c.error("Debug Data:") - c.error("Holdreflect:", con.HoldReflect) - c.error("Holdreflect.Kind():", con.HoldReflect.Kind()) - if !c.config.SuperDebug { - c.error("cur.Kind():", cur.Kind().String()) - } - c.error("") - if !multiline { - panic(con.VarHolder + varBit + "^\n" + "Invalid value. Maybe, it doesn't exist?") - } - panic(varBit + "^\n" + "Invalid value. Maybe, it doesn't exist?") - } + cur = c.skipStructPointers(cur, id) + c.checkIfValid(cur, con.VarHolder, con.HoldReflect, varBit, multiline) c.detail("in-loop varBit: " + varBit) if cur.Kind() == reflect.Map { cur = cur.MapIndex(reflect.ValueOf(id)) varBit += "[\"" + id + "\"]" - cur = skipPointers(cur, id) + cur = c.skipStructPointers(cur, id) if cur.Kind() == reflect.Struct || cur.Kind() == reflect.Interface { // TODO: Move the newVarByte declaration to the top level or to the if level, if a dispInt is only used in a particular if statement @@ -1385,15 +1389,60 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod con.TemplateName = fname if node.Pipe != nil { for _, cmd := range node.Pipe.Cmds { - firstWord := cmd.Args[0] - switch firstWord.(type) { + switch p := cmd.Args[0].(type) { + case *parse.FieldNode: + // TODO: Incomplete but it should cover the basics + cur := pcon.HoldReflect + + var varBit string + if cur.Kind() == reflect.Interface { + cur = cur.Elem() + varBit += ".(" + cur.Type().Name() + ")" + } + + for _, id := range p.Ident { + c.detail("Data Kind:", cur.Kind().String()) + c.detail("Field Bit:", id) + cur = c.skipStructPointers(cur, id) + c.checkIfValid(cur, pcon.VarHolder, pcon.HoldReflect, varBit, false) + + if cur.Kind() != reflect.Interface { + cur = cur.FieldByName(id) + varBit += "." + id + } + + // TODO: Handle deeply nested pointers mixed with interfaces mixed with pointers better + if cur.Kind() == reflect.Interface { + cur = cur.Elem() + varBit += ".(" + // TODO: Surely, there's a better way of doing this? + if cur.Type().PkgPath() != "main" && cur.Type().PkgPath() != "" { + c.importMap["html/template"] = "html/template" + varBit += strings.TrimPrefix(cur.Type().PkgPath(), "html/") + "." + } + varBit += cur.Type().Name() + ")" + } + } + con.VarHolder = pcon.VarHolder + varBit + con.HoldReflect = cur case *parse.DotNode: con.VarHolder = pcon.VarHolder con.HoldReflect = pcon.HoldReflect case *parse.NilNode: panic("Nil is not a command x.x") default: - c.detail("Unknown Node: ", firstWord) + c.critical("Unknown Param Type:", p) + pvar := reflect.ValueOf(p) + c.critical("param kind:", pvar.Kind().String()) + c.critical("param type:", pvar.Type().Name()) + if pvar.Kind() == reflect.Ptr { + c.critical("Looping over pointer") + for pvar.Kind() == reflect.Ptr { + pvar = pvar.Elem() + } + c.critical("concrete kind:", pvar.Kind().String()) + c.critical("concrete type:", pvar.Type().Name()) + } panic("") } } @@ -1527,3 +1576,7 @@ func (c *CTemplateSet) error(args ...interface{}) { log.Println(args...) } } + +func (c *CTemplateSet) critical(args ...interface{}) { + log.Println(args...) +} diff --git a/public/global.js b/public/global.js index c7eeb8b3..4fe797f0 100644 --- a/public/global.js +++ b/public/global.js @@ -388,17 +388,19 @@ function mainInit(){ $('.show_on_edit').removeClass("edit_opened"); runHook("close_edit"); - let formAction = this.form.getAttribute("action"); $.ajax({ - url: formAction, + url: this.form.getAttribute("action"), type: "POST", dataType: "json", - error: ajaxError, data: { topic_name: topicNameInput, topic_status: topicStatusInput, topic_content: topicContentInput, - topic_js: 1 + js: 1 + }, + error: ajaxError, + success: (data,status,xhr) => { + if("Content" in data) $(".topic_content").html(data["Content"]); } }); }); diff --git a/routes/topic.go b/routes/topic.go index 6525a1f8..a46dcfd9 100644 --- a/routes/topic.go +++ b/routes/topic.go @@ -616,10 +616,22 @@ func EditTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, s return common.InternalErrorJSQ(err, w, r, isJs) } + // TODO: Avoid the load to get this faster? + topic, err = common.Topics.Get(topic.ID) + if err == sql.ErrNoRows { + return common.PreErrorJSQ("The updated topic doesn't exist.", w, r, isJs) + } else if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + if !isJs { http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) } else { - _, _ = w.Write(successJSONBytes) + outBytes, err := json.Marshal(JsonReply{common.ParseMessage(topic.Content, topic.ParentID, "forums")}) + if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + w.Write(outBytes) } return nil } diff --git a/templates/topic_alt.html b/templates/topic_alt.html index e990c1b7..6c3861c3 100644 --- a/templates/topic_alt.html +++ b/templates/topic_alt.html @@ -14,7 +14,7 @@

{{.Topic.Title}}

- / + - {{.Forum.Name}} {{/** TODO: Does this need to be guarded by a permission? It's only visible in edit mode anyway, which can't be triggered, if they don't have the permission **/}} {{if .CurrentUser.Loggedin}} @@ -68,13 +68,7 @@ {{end}}
-
-
 
-
- - {{if .Topic.Tag}}
{{else}}
{{end}} -
-
+ {{template "topic_alt_userinfo.html" .Topic }}
{{.Topic.ContentHTML}}
{{if .CurrentUser.Loggedin}}{{if .CurrentUser.Perms.EditTopic}} @@ -131,44 +125,7 @@ {{if .CurrentUser.Loggedin}} {{if .CurrentUser.Perms.CreateReply}} {{if not .Topic.IsClosed or .CurrentUser.Perms.CloseTopic}} -
-
-
 
-
- - {{if .CurrentUser.Tag}}
{{else}}
{{end}} -
-
-
- - - -
-
- -
-
-
-
-
- - - -
-
-
-
-
- - - {{if .CurrentUser.Perms.UploadFiles}} - - -
{{end}} -
-
-
-
+{{template "topic_alt_quick_reply.html" . }} {{end}} {{end}} {{end}} diff --git a/templates/topic_alt_posts.html b/templates/topic_alt_posts.html index 008455b2..7198472a 100644 --- a/templates/topic_alt_posts.html +++ b/templates/topic_alt_posts.html @@ -1,11 +1,5 @@ {{range .ItemList}}
-
-
 
-
- - {{if .Tag}}
{{else}}
{{end}} -
-
+ {{template "topic_alt_userinfo.html" . }}
{{if .ActionType}} diff --git a/templates/topic_alt_quick_reply.html b/templates/topic_alt_quick_reply.html new file mode 100644 index 00000000..249cef5c --- /dev/null +++ b/templates/topic_alt_quick_reply.html @@ -0,0 +1,38 @@ +
+
+
 
+
+ + {{if .CurrentUser.Tag}}
{{else}}
{{end}} +
+
+
+
+ + +
+
+ +
+
+
+
+
+ + + +
+
+
+
+
+ + + {{if .CurrentUser.Perms.UploadFiles}} + + +
{{end}} +
+
+
+
\ No newline at end of file diff --git a/templates/topic_alt_userinfo.html b/templates/topic_alt_userinfo.html new file mode 100644 index 00000000..f1e12107 --- /dev/null +++ b/templates/topic_alt_userinfo.html @@ -0,0 +1,7 @@ +
+
 
+
+ + {{if .Tag}}
{{else}}
{{end}} +
+
\ No newline at end of file diff --git a/templates/topics.html b/templates/topics.html index da3487a9..659061d8 100644 --- a/templates/topics.html +++ b/templates/topics.html @@ -8,7 +8,7 @@