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.
This commit is contained in:
parent
f4337536dc
commit
a1a90ab9fd
|
@ -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...)
|
||||
}
|
||||
|
|
|
@ -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"]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<form action='/topic/edit/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}' method="post">
|
||||
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.IsClosed}} topic_closed_head{{end}}">
|
||||
<h1 class='topic_name hide_on_edit' title='{{.Topic.Title}}'>{{.Topic.Title}}</h1>
|
||||
<span class="topic_name_forum_sep hide_on_edit"> / </span>
|
||||
<span class="topic_name_forum_sep hide_on_edit"> - </span>
|
||||
<a href="{{.Forum.Link}}" class="topic_forum hide_on_edit">{{.Forum.Name}}</a>
|
||||
{{/** 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 @@
|
|||
</article>
|
||||
{{end}}
|
||||
<article {{scope "opening_post"}} itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item top_post" aria-label="{{lang "topic.opening_post_aria"}}">
|
||||
<div class="userinfo" aria-label="{{lang "topic.userinfo_aria"}}">
|
||||
<div class="avatar_item" style="background-image: url({{.Topic.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<div class="user_meta">
|
||||
<a href="{{.Topic.UserLink}}" class="the_name" rel="author">{{.Topic.CreatedByName}}</a>
|
||||
{{if .Topic.Tag}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">{{.Topic.Tag}}</div><div class="tag_post"></div></div>{{else}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">{{level .Topic.Level}}</div><div class="tag_post"></div></div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "topic_alt_userinfo.html" .Topic }}
|
||||
<div class="content_container">
|
||||
<div class="hide_on_edit topic_content user_content" itemprop="text">{{.Topic.ContentHTML}}</div>
|
||||
{{if .CurrentUser.Loggedin}}{{if .CurrentUser.Perms.EditTopic}}<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea>
|
||||
|
@ -131,44 +125,7 @@
|
|||
{{if .CurrentUser.Loggedin}}
|
||||
{{if .CurrentUser.Perms.CreateReply}}
|
||||
{{if not .Topic.IsClosed or .CurrentUser.Perms.CloseTopic}}
|
||||
<div class="rowblock topic_reply_container">
|
||||
<div class="userinfo" aria-label="{{lang "topic.your_information"}}">
|
||||
<div class="avatar_item" style="background-image: url({{.CurrentUser.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<div class="user_meta">
|
||||
<a href="{{.CurrentUser.Link}}" class="the_name" rel="author">{{.CurrentUser.Name}}</a>
|
||||
{{if .CurrentUser.Tag}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">{{.CurrentUser.Tag}}</div><div class="tag_post"></div></div>{{else}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">{{level .CurrentUser.Level}}</div><div class="tag_post"></div></div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="rowblock topic_reply_form quick_create_form" aria-label="{{lang "topic.reply_aria"}}">
|
||||
<form id="quick_post_form" enctype="multipart/form-data" action="/reply/create/?session={{.CurrentUser.Session}}" method="post"></form>
|
||||
<input form="quick_post_form" name="tid" value='{{.Topic.ID}}' type="hidden" />
|
||||
<input form="quick_post_form" id="has_poll_input" name="has_poll" value="0" type="hidden" />
|
||||
<div class="formrow real_first_child">
|
||||
<div class="formitem">
|
||||
<textarea id="input_content" form="quick_post_form" name="reply-content" placeholder="{{lang "topic.reply_content_alt"}}" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formrow poll_content_row auto_hide">
|
||||
<div class="formitem">
|
||||
<div class="pollinput" data-pollinput="0">
|
||||
<input type="checkbox" disabled />
|
||||
<label class="pollinputlabel"></label>
|
||||
<input form="quick_post_form" name="pollinputitem[0]" class="pollinputinput" type="text" placeholder="{{lang "topic.reply_add_poll_option"}}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formrow quick_button_row">
|
||||
<div class="formitem">
|
||||
<button form="quick_post_form" name="reply-button" class="formbutton">{{lang "topic.reply_button"}}</button>
|
||||
<button form="quick_post_form" class="formbutton" id="add_poll_button">{{lang "topic.reply_add_poll_button"}}</button>
|
||||
{{if .CurrentUser.Perms.UploadFiles}}
|
||||
<input name="upload_files" form="quick_post_form" id="upload_files" multiple type="file" style="display: none;" />
|
||||
<label for="upload_files" class="formbutton add_file_button">{{lang "topic.reply_add_file_button"}}</label>
|
||||
<div id="upload_file_dock"></div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "topic_alt_quick_reply.html" . }}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -1,11 +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}}">
|
||||
<div class="userinfo" aria-label="{{lang "topic.userinfo_aria"}}">
|
||||
<div class="avatar_item" style="background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<div class="user_meta">
|
||||
<a href="{{.UserLink}}" class="the_name" rel="author">{{.CreatedByName}}</a>
|
||||
{{if .Tag}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">{{.Tag}}</div><div class="tag_post"></div></div>{{else}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">{{level .Level}}</div><div class="tag_post"></div></div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "topic_alt_userinfo.html" . }}
|
||||
<div class="content_container"{{if .ActionType}} style="margin-left: 0px;"{{end}}>
|
||||
{{if .ActionType}}
|
||||
<span class="action_icon" style="font-size: 18px;padding-right: 5px;" aria-hidden="true">{{.ActionIcon}}</span>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<div class="rowblock topic_reply_container">
|
||||
<div class="userinfo" aria-label="{{lang "topic.your_information"}}">
|
||||
<div class="avatar_item" style="background-image: url({{.CurrentUser.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<div class="user_meta">
|
||||
<a href="{{.CurrentUser.Link}}" class="the_name" rel="author">{{.CurrentUser.Name}}</a>
|
||||
{{if .CurrentUser.Tag}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">{{.CurrentUser.Tag}}</div><div class="tag_post"></div></div>{{else}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">{{level .CurrentUser.Level}}</div><div class="tag_post"></div></div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="rowblock topic_reply_form quick_create_form" aria-label="{{lang "topic.reply_aria"}}">
|
||||
<form id="quick_post_form" enctype="multipart/form-data" action="/reply/create/?session={{.CurrentUser.Session}}" method="post"></form>
|
||||
<input form="quick_post_form" name="tid" value='{{.Topic.ID}}' type="hidden" />
|
||||
<input form="quick_post_form" id="has_poll_input" name="has_poll" value="0" type="hidden" />
|
||||
<div class="formrow real_first_child">
|
||||
<div class="formitem">
|
||||
<textarea id="input_content" form="quick_post_form" name="reply-content" placeholder="{{lang "topic.reply_content_alt"}}" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formrow poll_content_row auto_hide">
|
||||
<div class="formitem">
|
||||
<div class="pollinput" data-pollinput="0">
|
||||
<input type="checkbox" disabled />
|
||||
<label class="pollinputlabel"></label>
|
||||
<input form="quick_post_form" name="pollinputitem[0]" class="pollinputinput" type="text" placeholder="{{lang "topic.reply_add_poll_option"}}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formrow quick_button_row">
|
||||
<div class="formitem">
|
||||
<button form="quick_post_form" name="reply-button" class="formbutton">{{lang "topic.reply_button"}}</button>
|
||||
<button form="quick_post_form" class="formbutton" id="add_poll_button">{{lang "topic.reply_add_poll_button"}}</button>
|
||||
{{if .CurrentUser.Perms.UploadFiles}}
|
||||
<input name="upload_files" form="quick_post_form" id="upload_files" multiple type="file" style="display: none;" />
|
||||
<label for="upload_files" class="formbutton add_file_button">{{lang "topic.reply_add_file_button"}}</label>
|
||||
<div id="upload_file_dock"></div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,7 @@
|
|||
<div class="userinfo" aria-label="{{lang "topic.userinfo_aria"}}">
|
||||
<div class="avatar_item" style="background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<div class="user_meta">
|
||||
<a href="{{.UserLink}}" class="the_name" rel="author">{{.CreatedByName}}</a>
|
||||
{{if .Tag}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">{{.Tag}}</div><div class="tag_post"></div></div>{{else}}<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">{{level .Level}}</div><div class="tag_post"></div></div>{{end}}
|
||||
</div>
|
||||
</div>
|
|
@ -8,7 +8,7 @@
|
|||
<div class="optbox">
|
||||
{{if .ForumList}}
|
||||
<div class="opt filter_opt">
|
||||
<a class="filter_opt_sep"> / </a>
|
||||
<a class="filter_opt_sep"> - </a>
|
||||
<a href="#" class="filter_opt_label link_label" data-for="topic_list_filter_select">{{if eq .Sort.SortBy "mostviewed" }}{{lang "topic_list.most_viewed_filter"}}{{else}}{{lang "topic_list.most_recent_filter"}}{{end}} <span class="filter_opt_pointy">▾</span></a>
|
||||
<div id="topic_list_filter_select" class="link_select">
|
||||
<div class="link_option link_selected">
|
||||
|
|
Loading…
Reference in New Issue