Improved the poll UIs slightly.
Polls without any votes should look a little nicer now. .hide_on_edit and other similar classes should now override other classes on Cosora. Added <red> to avoid having to use inline styles for parser errors. Reorganised a few elements in topic.html and topic_alt.html Split topic_poll.html out of topic.html Fixed a bug where attachments were getting assigned to the wrong reply / topic. Added the router_after_filters hook. Added the topic.poll_no_results phrase. Added two parser tests.
This commit is contained in:
parent
d5acb92aef
commit
5808f1d0ba
@ -277,6 +277,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||
tblColumn{"originTable", "varchar", 200, false, false, "replies"},
|
||||
tblColumn{"uploadedBy", "int", 0, false, false, ""}, // TODO; Make this a foreign key
|
||||
tblColumn{"path", "varchar", 200, false, false, ""},
|
||||
//tblColumn{"extra", "varchar", 200, false, false, ""},
|
||||
},
|
||||
[]tblKey{
|
||||
tblKey{"attachID", "primary"},
|
||||
|
@ -81,7 +81,7 @@ func (store *DefaultAttachmentStore) BulkMiniGetList(originTable string, ids []i
|
||||
}
|
||||
if len(ids) == 1 {
|
||||
res, err := store.MiniGetList(originTable, ids[0])
|
||||
return map[int][]*MiniAttachment{0: res}, err
|
||||
return map[int][]*MiniAttachment{ids[0]: res}, err
|
||||
}
|
||||
|
||||
amap = make(map[int][]*MiniAttachment)
|
||||
|
@ -88,7 +88,8 @@ var hookTable = &HookTable{
|
||||
"action_end_edit_reply": nil,
|
||||
"action_end_delete_reply": nil,
|
||||
|
||||
"router_pre_route": nil,
|
||||
"router_after_filters": nil,
|
||||
"router_pre_route": nil,
|
||||
},
|
||||
map[string][]func(string) string{
|
||||
"preparse_preassign": nil,
|
||||
|
@ -9,13 +9,14 @@ import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// TODO: Somehow localise these?
|
||||
var SpaceGap = []byte(" ")
|
||||
var httpProtBytes = []byte("http://")
|
||||
var InvalidURL = []byte("<span style='color: red;'>[Invalid URL]</span>")
|
||||
var InvalidTopic = []byte("<span style='color: red;'>[Invalid Topic]</span>")
|
||||
var InvalidProfile = []byte("<span style='color: red;'>[Invalid Profile]</span>")
|
||||
var InvalidForum = []byte("<span style='color: red;'>[Invalid Forum]</span>")
|
||||
var unknownMedia = []byte("<span style='color: red;'>[Unknown Media]</span>")
|
||||
var InvalidURL = []byte("<red>[Invalid URL]</red>")
|
||||
var InvalidTopic = []byte("<red>[Invalid Topic]</red>")
|
||||
var InvalidProfile = []byte("<red>[Invalid Profile]</red>")
|
||||
var InvalidForum = []byte("<red>[Invalid Forum]</red>")
|
||||
var unknownMedia = []byte("<red>[Unknown Media]</red>")
|
||||
var URLOpen = []byte("<a href='")
|
||||
var URLOpen2 = []byte("'>")
|
||||
var bytesSinglequote = []byte("'")
|
||||
|
@ -792,11 +792,17 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
req.URL.Path = req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1]
|
||||
}
|
||||
|
||||
// TODO: Use the same hook table as downstream
|
||||
hTbl := common.GetHookTable()
|
||||
skip, ferr := hTbl.VhookSkippable("router_after_filters", w, req, prefix, extraData)
|
||||
if skip || ferr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if prefix != "/ws" {
|
||||
h := w.Header()
|
||||
h.Set("X-Frame-Options", "deny")
|
||||
h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing
|
||||
// TODO: Set the content policy header
|
||||
h.Set("X-Content-Type-Options", "nosniff")
|
||||
}
|
||||
|
||||
@ -994,9 +1000,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
w = common.GzipResponseWriter{Writer: gz, ResponseWriter: w}
|
||||
}
|
||||
|
||||
// TODO: Use the same hook table as downstream
|
||||
hTbl := common.GetHookTable()
|
||||
skip, ferr := hTbl.VhookSkippable("router_pre_route", w, req, user, prefix, extraData)
|
||||
skip, ferr = hTbl.VhookSkippable("router_pre_route", w, req, user, prefix, extraData)
|
||||
if skip || ferr != nil {
|
||||
r.handleError(ferr,w,req,user)
|
||||
}
|
||||
|
@ -597,6 +597,7 @@
|
||||
"topic.poll_vote":"Vote",
|
||||
"topic.poll_results":"Results",
|
||||
"topic.poll_cancel":"Cancel",
|
||||
"topic.poll_no_results":"No one has voted yet.",
|
||||
"topic.post_controls_aria":"Controls and Author Information",
|
||||
"topic.unlike_tooltip":"Unlike",
|
||||
"topic.unlike_aria":"Unlike this topic",
|
||||
|
@ -143,11 +143,13 @@ func TestParser(t *testing.T) {
|
||||
msgList.Add("//"+common.Site.URL+"\n//"+common.Site.URL, "<a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a><br><a href='//"+common.Site.URL+"'>//"+common.Site.URL+"</a>")
|
||||
|
||||
msgList.Add("#tid-1", "<a href='/topic/1'>#tid-1</a>")
|
||||
msgList.Add("#tid-0", "<red>[Invalid Topic]</red>")
|
||||
msgList.Add("https://"+url+"/#tid-1", "<a href='https://"+url+"/#tid-1'>https://"+url+"/#tid-1</a>")
|
||||
msgList.Add("#fid-1", "<a href='/forum/1'>#fid-1</a>")
|
||||
msgList.Add("#fid-0", "<red>[Invalid Forum]</red>")
|
||||
msgList.Add("@1", "<a href='/user/admin.1' class='mention'>@Admin</a>")
|
||||
msgList.Add("@0", "<span style='color: red;'>[Invalid Profile]</span>")
|
||||
msgList.Add("@-1", "<span style='color: red;'>[Invalid Profile]</span>1")
|
||||
msgList.Add("@0", "<red>[Invalid Profile]</red>")
|
||||
msgList.Add("@-1", "<red>[Invalid Profile]</red>1")
|
||||
|
||||
for _, item := range msgList.Items {
|
||||
res := common.ParseMessage(item.Msg, 1, "forums")
|
||||
|
@ -32,9 +32,9 @@ func init() {
|
||||
func initBbcode(plugin *common.Plugin) error {
|
||||
plugin.AddHook("parse_assign", bbcodeFullParse)
|
||||
|
||||
bbcodeInvalidNumber = []byte("<span style='color: red;'>[Invalid Number]</span>")
|
||||
bbcodeNoNegative = []byte("<span style='color: red;'>[No Negative Numbers]</span>")
|
||||
bbcodeMissingTag = []byte("<span style='color: red;'>[Missing Tag]</span>")
|
||||
bbcodeInvalidNumber = []byte("<red>[Invalid Number]</red>")
|
||||
bbcodeNoNegative = []byte("<red>[No Negative Numbers]</red>")
|
||||
bbcodeMissingTag = []byte("<red>[Missing Tag]</red>")
|
||||
|
||||
bbcodeBold = regexp.MustCompile(`(?s)\[b\](.*)\[/b\]`)
|
||||
bbcodeItalic = regexp.MustCompile(`(?s)\[i\](.*)\[/i\]`)
|
||||
|
@ -29,7 +29,7 @@ func init() {
|
||||
func initMarkdown(plugin *common.Plugin) error {
|
||||
plugin.AddHook("parse_assign", markdownParse)
|
||||
|
||||
markdownUnclosedElement = []byte("<span style='color: red;'>[Unclosed Element]</span>")
|
||||
markdownUnclosedElement = []byte("<red>[Unclosed Element]</red>")
|
||||
|
||||
markdownBoldTagOpen = []byte("<b>")
|
||||
markdownBoldTagClose = []byte("</b>")
|
||||
@ -63,7 +63,7 @@ func markdownParse(msg string) string {
|
||||
// Under Construction!
|
||||
func _markdownParse(msg string, n int) string {
|
||||
if n > markdownMaxDepth {
|
||||
return "<span style='color: red;'>[Markdown Error: Overflowed the max depth of 20]</span>"
|
||||
return "<red>[Markdown Error: Overflowed the max depth of 20]</red>"
|
||||
}
|
||||
|
||||
var outbytes []byte
|
||||
|
@ -87,7 +87,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||
var expects string
|
||||
|
||||
msg = "[rand][/rand]"
|
||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand][/rand]"
|
||||
expects = "<red>[Invalid Number]</red>[rand][/rand]"
|
||||
t.Log("Testing string '" + msg + "'")
|
||||
res = bbcodeFullParse(msg)
|
||||
if res != expects {
|
||||
@ -96,7 +96,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||
}
|
||||
|
||||
msg = "[rand]-1[/rand]"
|
||||
expects = "<span style='color: red;'>[No Negative Numbers]</span>[rand]-1[/rand]"
|
||||
expects = "<red>[No Negative Numbers]</red>[rand]-1[/rand]"
|
||||
t.Log("Testing string '" + msg + "'")
|
||||
res = bbcodeFullParse(msg)
|
||||
if res != expects {
|
||||
@ -105,7 +105,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||
}
|
||||
|
||||
msg = "[rand]-01[/rand]"
|
||||
expects = "<span style='color: red;'>[No Negative Numbers]</span>[rand]-01[/rand]"
|
||||
expects = "<red>[No Negative Numbers]</red>[rand]-01[/rand]"
|
||||
t.Log("Testing string '" + msg + "'")
|
||||
res = bbcodeFullParse(msg)
|
||||
if res != expects {
|
||||
@ -114,7 +114,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||
}
|
||||
|
||||
msg = "[rand]NaN[/rand]"
|
||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]NaN[/rand]"
|
||||
expects = "<red>[Invalid Number]</red>[rand]NaN[/rand]"
|
||||
t.Log("Testing string '" + msg + "'")
|
||||
res = bbcodeFullParse(msg)
|
||||
if res != expects {
|
||||
@ -123,7 +123,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||
}
|
||||
|
||||
msg = "[rand]Inf[/rand]"
|
||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]Inf[/rand]"
|
||||
expects = "<red>[Invalid Number]</red>[rand]Inf[/rand]"
|
||||
t.Log("Testing string '" + msg + "'")
|
||||
res = bbcodeFullParse(msg)
|
||||
if res != expects {
|
||||
@ -132,7 +132,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||
}
|
||||
|
||||
msg = "[rand]+[/rand]"
|
||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]+[/rand]"
|
||||
expects = "<red>[Invalid Number]</red>[rand]+[/rand]"
|
||||
t.Log("Testing string '" + msg + "'")
|
||||
res = bbcodeFullParse(msg)
|
||||
if res != expects {
|
||||
@ -141,7 +141,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||
}
|
||||
|
||||
msg = "[rand]1+1[/rand]"
|
||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]1+1[/rand]"
|
||||
expects = "<red>[Invalid Number]</red>[rand]1+1[/rand]"
|
||||
t.Log("Testing string '" + msg + "'")
|
||||
res = bbcodeFullParse(msg)
|
||||
if res != expects {
|
||||
@ -191,7 +191,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||
t.Log("Testing string '" + msg + "'")
|
||||
res = bbcodeFullParse(msg)
|
||||
_, err = strconv.Atoi(res)
|
||||
if err != nil && res != "<span style='color: red;'>[Invalid Number]</span>[rand]18446744073709551615[/rand]" {
|
||||
if err != nil && res != "<red>[Invalid Number]</red>[rand]18446744073709551615[/rand]" {
|
||||
t.Error("Bad output:", "'"+res+"'")
|
||||
t.Error("Expected a number between 0 and 18446744073709551615")
|
||||
}
|
||||
@ -199,7 +199,7 @@ func TestBBCodeRender(t *testing.T) {
|
||||
t.Log("Testing string '" + msg + "'")
|
||||
res = bbcodeFullParse(msg)
|
||||
_, err = strconv.Atoi(res)
|
||||
if err != nil && res != "<span style='color: red;'>[Invalid Number]</span>[rand]170141183460469231731687303715884105727[/rand]" {
|
||||
if err != nil && res != "<red>[Invalid Number]</red>[rand]170141183460469231731687303715884105727[/rand]" {
|
||||
t.Error("Bad output:", "'"+res+"'")
|
||||
t.Error("Expected a number between 0 and 170141183460469231731687303715884105727")
|
||||
}
|
||||
|
@ -1170,13 +1170,24 @@ function mainInit(){
|
||||
//id="poll_results_{{.Poll.ID}}" class="poll_results auto_hide"
|
||||
$(".poll_results_button").click(function(){
|
||||
let pollID = $(this).attr("data-poll-id");
|
||||
$("#poll_results_" + pollID + " .user_content").html("<div id='poll_results_chart_"+pollID+"'></div>");
|
||||
$("#poll_results_" + pollID).removeClass("auto_hide");
|
||||
fetch("/poll/results/" + pollID, {
|
||||
credentials: 'same-origin'
|
||||
}).then((response) => response.text()).catch((error) => console.error("Error:",error)).then((rawData) => {
|
||||
// TODO: Make sure the received data is actually a list of integers
|
||||
let data = JSON.parse(rawData);
|
||||
|
||||
let allZero = true;
|
||||
for(let i = 0; i < data.length; i++) {
|
||||
if(data[i] != "0") allZero = false;
|
||||
}
|
||||
if(allZero) {
|
||||
$("#poll_results_" + pollID + " .poll_no_results").removeClass("auto_hide");
|
||||
console.log("all zero")
|
||||
return;
|
||||
}
|
||||
|
||||
$("#poll_results_" + pollID + " .user_content").html("<div id='poll_results_chart_"+pollID+"'></div>");
|
||||
console.log("rawData: ", rawData);
|
||||
console.log("series: ", data);
|
||||
Chartist.Pie('#poll_results_chart_' + pollID, {
|
||||
|
@ -571,11 +571,17 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
req.URL.Path = req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1]
|
||||
}
|
||||
|
||||
// TODO: Use the same hook table as downstream
|
||||
hTbl := common.GetHookTable()
|
||||
skip, ferr := hTbl.VhookSkippable("router_after_filters", w, req, prefix, extraData)
|
||||
if skip || ferr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if prefix != "/ws" {
|
||||
h := w.Header()
|
||||
h.Set("X-Frame-Options", "deny")
|
||||
h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing
|
||||
// TODO: Set the content policy header
|
||||
h.Set("X-Content-Type-Options", "nosniff")
|
||||
}
|
||||
|
||||
@ -773,9 +779,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
w = common.GzipResponseWriter{Writer: gz, ResponseWriter: w}
|
||||
}
|
||||
|
||||
// TODO: Use the same hook table as downstream
|
||||
hTbl := common.GetHookTable()
|
||||
skip, ferr := hTbl.VhookSkippable("router_pre_route", w, req, user, prefix, extraData)
|
||||
skip, ferr = hTbl.VhookSkippable("router_pre_route", w, req, user, prefix, extraData)
|
||||
if skip || ferr != nil {
|
||||
r.handleError(ferr,w,req,user)
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
{{template "header.html" . }}
|
||||
|
||||
<form id="edit_topic_form" action='/topic/edit/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}' method="post"></form>
|
||||
{{if gt .Page 1}}<link rel="prev" href="{{.Topic.Link}}?page={{subtract .Page 1}}" />
|
||||
<div id="prevFloat" class="prev_button"><a class="prev_link" aria-label="{{lang "paginator.prev_page_aria"}}" rel="prev" href="{{.Topic.Link}}?page={{subtract .Page 1}}">{{lang "paginator.less_than"}}</a></div>{{end}}
|
||||
|
||||
@ -9,9 +8,9 @@
|
||||
<a class="next_link" aria-label="{{lang "paginator.next_page_aria"}}" rel="next" href="{{.Topic.Link}}?page={{add .Page 1}}">{{lang "paginator.greater_than"}}</a>
|
||||
</div>{{end}}
|
||||
|
||||
<link rel="canonical" href="//{{.Site.URL}}{{.Topic.Link}}{{if gt .Page 1}}?page={{.Page}}{{end}}" />
|
||||
<main id="topicPage">
|
||||
|
||||
<main>
|
||||
<link rel="canonical" href="//{{.Site.URL}}{{.Topic.Link}}{{if gt .Page 1}}?page={{.Page}}{{end}}" />
|
||||
|
||||
<div {{scope "topic_title_block"}} class="rowblock rowhead topic_block" aria-label="{{lang "topic.opening_post_aria"}}">
|
||||
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.IsClosed}} topic_closed_head{{end}}">
|
||||
@ -20,6 +19,7 @@
|
||||
{{/** 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 not .Topic.IsClosed or .CurrentUser.Perms.CloseTopic}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}
|
||||
<form id="edit_topic_form" action='/topic/edit/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}' method="post"></form>
|
||||
<input form='edit_topic_form' class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" aria-label="{{lang "topic.title_input_aria"}}" />
|
||||
<button form='edit_topic_form' name="topic-button" class="formbutton show_on_edit submit_edit">{{lang "topic.update_button"}}</button>
|
||||
{{end}}
|
||||
@ -27,29 +27,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{{if .Poll.ID}}
|
||||
<article class="rowblock post_container poll" aria-level="{{lang "topic.poll_aria"}}">
|
||||
<div class="rowitem passive editable_parent post_item poll_item {{.Topic.ClassName}}" style="background-image: url({{.Topic.Avatar}}), url(/static/{{.Header.Theme.Name}}/post-avatar-bg.jpg);background-position: 0px {{if le .Topic.ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;">
|
||||
<div class="topic_content user_content" style="margin:0;padding:0;">
|
||||
{{range .Poll.QuickOptions}}
|
||||
<div class="poll_option">
|
||||
<input form="poll_{{$.Poll.ID}}_form" id="poll_option_{{.ID}}" name="poll_option_input" type="checkbox" value="{{.ID}}" />
|
||||
<label class="poll_option_label" for="poll_option_{{.ID}}">
|
||||
<div class="sel"></div>
|
||||
</label>
|
||||
<span id="poll_option_text_{{.ID}}" class="poll_option_text">{{.Value}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="poll_buttons">
|
||||
<button form="poll_{{.Poll.ID}}_form" class="poll_vote_button">{{lang "topic.poll_vote"}}</button>
|
||||
<button class="poll_results_button" data-poll-id="{{.Poll.ID}}">{{lang "topic.poll_results"}}</button>
|
||||
<a href="#"><button class="poll_cancel_button">{{lang "topic.poll_cancel"}}</button></a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="poll_results_{{.Poll.ID}}" class="poll_results auto_hide">
|
||||
<div class="topic_content user_content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{{template "topic_poll.html" . }}
|
||||
{{end}}
|
||||
|
||||
<article {{scope "opening_post"}} itemscope itemtype="http://schema.org/CreativeWork" class="rowblock post_container top_post" aria-label="{{lang "topic.opening_post_aria"}}">
|
||||
@ -127,4 +105,4 @@
|
||||
|
||||
</main>
|
||||
|
||||
{{template "footer.html" . }}
|
||||
{{template "footer.html" . }}
|
@ -6,30 +6,29 @@
|
||||
{{if ne .LastPage .Page}}<link rel="prerender next" href="{{.Topic.Link}}?page={{add .Page 1}}" />
|
||||
<div id="nextFloat" class="next_button"><a class="next_link" aria-label="{{lang "paginator.next_page_aria"}}" rel="next" href="{{.Topic.Link}}?page={{add .Page 1}}">{{lang "paginator.greater_than"}}</a></div>{{end}}
|
||||
|
||||
<main id="topicPage">
|
||||
|
||||
<link rel="canonical" href="//{{.Site.URL}}{{.Topic.Link}}{{if gt .Page 1}}?page={{.Page}}{{end}}" />
|
||||
|
||||
<main>
|
||||
|
||||
<div {{scope "topic_title_block"}} class="rowblock rowhead topic_block" aria-label="{{lang "topic.opening_post_aria"}}">
|
||||
<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>
|
||||
<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}}
|
||||
{{if not .Topic.IsClosed or .CurrentUser.Perms.CloseTopic}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}
|
||||
<input class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" aria-label="{{lang "topic.title_input_aria"}}" />
|
||||
<button name="topic-button" class="formbutton show_on_edit submit_edit">{{lang "topic.update_button"}}</button>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
<span class="topic_view_count hide_on_edit">{{.Topic.ViewCount}}</span>
|
||||
{{/** TODO: Inline this CSS **/}}
|
||||
{{if .Topic.IsClosed}}<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='{{lang "status.closed_tooltip"}}' aria-label='{{lang "topic.status_closed_aria"}}' style="font-weight:normal;float: right;position:relative;top:-5px;">🔒︎</span>{{end}}
|
||||
</div>
|
||||
</form>
|
||||
<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>
|
||||
<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}}
|
||||
{{if not .Topic.IsClosed or .CurrentUser.Perms.CloseTopic}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}
|
||||
<form id="edit_topic_form" action='/topic/edit/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}' method="post"></form>
|
||||
<input form="edit_topic_form" class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" aria-label="{{lang "topic.title_input_aria"}}" />
|
||||
<button form="edit_topic_form" name="topic-button" class="formbutton show_on_edit submit_edit">{{lang "topic.update_button"}}</button>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
<span class="topic_view_count hide_on_edit">{{.Topic.ViewCount}}</span>
|
||||
{{/** TODO: Inline this CSS **/}}
|
||||
{{if .Topic.IsClosed}}<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='{{lang "status.closed_tooltip"}}' aria-label='{{lang "topic.status_closed_aria"}}' style="font-weight:normal;float: right;position:relative;top:-5px;">🔒︎</span>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rowblock post_container">
|
||||
@ -56,7 +55,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="poll_results_{{.Poll.ID}}" class="content_container poll_results auto_hide">
|
||||
<div class="topic_content user_content"></div>
|
||||
<div class="topic_content user_content">
|
||||
<div class="auto_hide poll_no_results">{{lang "topic.poll_no_results"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{{end}}
|
||||
|
@ -11,20 +11,20 @@
|
||||
|
||||
{{if $.CurrentUser.Perms.EditReply}}
|
||||
{{if .Attachments}}<div class="show_on_edit show_on_block_edit attach_edit_bay" type="reply" id="{{.ID}}">
|
||||
{{range .Attachments}}
|
||||
<div class="attach_item{{if .Image}} attach_image_holder{{end}}">
|
||||
{{if .Image}}<img src="//{{$.Header.Site.URL}}/attachs/{{.Path}}?sectionID={{.SectionID}}&sectionType=forums" height=24 width=24 />{{end}}
|
||||
<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>
|
||||
{{end}}
|
||||
<div class="attach_item attach_item_buttons">
|
||||
{{if $.CurrentUser.Perms.UploadFiles}}
|
||||
<input name="upload_files" class="upload_files_post" id="upload_files_post_{{.ID}}" multiple type="file" style="display: none;" />
|
||||
<label for="upload_files_post_{{.ID}}" class="formbutton add_file_button">{{lang "topic.upload_button_text"}}</label>{{end}}
|
||||
<button class="attach_item_delete">{{lang "topic.delete_button_text"}}</button>
|
||||
</div>
|
||||
{{range .Attachments}}
|
||||
<div class="attach_item{{if .Image}} attach_image_holder{{end}}">
|
||||
{{if .Image}}<img src="//{{$.Header.Site.URL}}/attachs/{{.Path}}?sectionID={{.SectionID}}&sectionType=forums" height=24 width=24 />{{end}}
|
||||
<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>
|
||||
{{end}}
|
||||
<div class="attach_item attach_item_buttons">
|
||||
{{if $.CurrentUser.Perms.UploadFiles}}
|
||||
<input name="upload_files" class="upload_files_post auto_hide" id="upload_files_post_{{.ID}}" multiple type="file" />
|
||||
<label for="upload_files_post_{{.ID}}" class="formbutton add_file_button">{{lang "topic.upload_button_text"}}</label>{{end}}
|
||||
<button class="attach_item_delete">{{lang "topic.delete_button_text"}}</button>
|
||||
</div>
|
||||
</div>{{end}}
|
||||
{{end}}{{end}}
|
||||
|
||||
|
25
templates/topic_poll.html
Normal file
25
templates/topic_poll.html
Normal file
@ -0,0 +1,25 @@
|
||||
<article class="rowblock post_container poll" aria-level="{{lang "topic.poll_aria"}}">
|
||||
<div class="rowitem passive editable_parent post_item poll_item {{.Topic.ClassName}}" style="background-image: url({{.Topic.Avatar}}), url(/static/{{.Header.Theme.Name}}/post-avatar-bg.jpg);background-position: 0px {{if le .Topic.ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;">
|
||||
<div class="topic_content user_content">
|
||||
{{range .Poll.QuickOptions}}
|
||||
<div class="poll_option">
|
||||
<input form="poll_{{$.Poll.ID}}_form" id="poll_option_{{.ID}}" name="poll_option_input" type="checkbox" value="{{.ID}}" />
|
||||
<label class="poll_option_label" for="poll_option_{{.ID}}">
|
||||
<div class="sel"></div>
|
||||
</label>
|
||||
<span id="poll_option_text_{{.ID}}" class="poll_option_text">{{.Value}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="poll_buttons">
|
||||
<button form="poll_{{.Poll.ID}}_form" class="poll_vote_button">{{lang "topic.poll_vote"}}</button>
|
||||
<button class="poll_results_button" data-poll-id="{{.Poll.ID}}">{{lang "topic.poll_results"}}</button>
|
||||
<a href="#"><button class="poll_cancel_button">{{lang "topic.poll_cancel"}}</button></a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="poll_results_{{.Poll.ID}}" class="poll_results auto_hide">
|
||||
<div class="topic_content user_content">
|
||||
<div class="auto_hide poll_no_results">{{lang "topic.poll_no_results"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
@ -521,10 +521,11 @@ input[type=checkbox] + label {
|
||||
background-color: var(--element-background-color);
|
||||
}
|
||||
input[type=checkbox]:checked + label .sel {
|
||||
display: inline-block;
|
||||
display: block;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: var(--element-border-color);
|
||||
margin-top: -2px;
|
||||
}
|
||||
.poll_content_row {
|
||||
padding-left: 20px;
|
||||
@ -544,7 +545,7 @@ input[type=checkbox]:checked + label .sel {
|
||||
.show_on_block_edit:not(.edit_opened),
|
||||
.hide_on_block_edit.edit_opened,
|
||||
.link_select:not(.link_opened) {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
input[type=checkbox] + label.poll_option_label {
|
||||
@ -552,20 +553,22 @@ input[type=checkbox] + label.poll_option_label {
|
||||
height: 18px;
|
||||
}
|
||||
input[type=checkbox]:checked + label.poll_option_label .sel {
|
||||
display: inline-block;
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-left: 3px;
|
||||
margin-top: 3px;
|
||||
background: var(--element-border-color);
|
||||
}
|
||||
/*.poll_option {
|
||||
margin-bottom: 3px;
|
||||
}*/
|
||||
.poll_option {
|
||||
padding-bottom: 5px;
|
||||
display: flex;
|
||||
}
|
||||
.poll_option_text {
|
||||
display: inline-block;
|
||||
margin-left: 3px;
|
||||
display: block;
|
||||
margin-left: 8px;
|
||||
margin-top: 1px;
|
||||
font-size: 15px;
|
||||
/*font-weight: bold;*/
|
||||
position: relative;
|
||||
top: -1px;
|
||||
color: var(--light-text-color);
|
||||
@ -587,6 +590,9 @@ input[type=checkbox]:checked + label.poll_option_label .sel {
|
||||
margin-left: 16px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.poll_results {
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
||||
.formbutton {
|
||||
margin-top: 12px;
|
||||
@ -1078,6 +1084,9 @@ blockquote:first-child {
|
||||
.user_content strong h2, .user_content strong h3, .user_content strong h4 {
|
||||
font-weight: bold;
|
||||
}
|
||||
red {
|
||||
color: red;
|
||||
}
|
||||
.button_container {
|
||||
margin-top: auto;
|
||||
display: flex;
|
||||
|
@ -868,6 +868,9 @@ blockquote:first-child {
|
||||
width: 100% !important;
|
||||
padding: 16px;
|
||||
}
|
||||
red {
|
||||
color: red;
|
||||
}
|
||||
.user_content.in_edit a {
|
||||
display: flex;
|
||||
background-color: #444444;
|
||||
@ -942,6 +945,9 @@ input[type=checkbox]:checked + label .sel {
|
||||
.poll_buttons button {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.poll_results {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.ip_item {
|
||||
display: none;
|
||||
|
@ -280,6 +280,9 @@ h1, h2, h3, h4, h5 {
|
||||
.user_content strong h2, .user_content strong h3, .user_content strong h4 {
|
||||
font-weight: bold;
|
||||
}
|
||||
red {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.controls {
|
||||
width: 100%;
|
||||
@ -682,6 +685,9 @@ input[type=checkbox]:checked + label.poll_option_label .sel {
|
||||
padding-bottom: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.poll_buttons > *:not(:first-child) {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.poll_results {
|
||||
margin-left: auto;
|
||||
max-height: 120px;
|
||||
|
@ -689,6 +689,9 @@ button.username {
|
||||
.user_content strong h2, .user_content strong h3, .user_content strong h4 {
|
||||
font-weight: bold;
|
||||
}
|
||||
red {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.user_tag {
|
||||
float: right;
|
||||
@ -859,6 +862,9 @@ input[type=checkbox]:checked + label.poll_option_label .sel {
|
||||
padding-bottom: 3px;
|
||||
border: 1px solid hsl(0, 0%, 70%);
|
||||
}
|
||||
.poll_buttons > *:not(:first-child) {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.poll_results {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user