From 5808f1d0ba4c3ef7172107273db3312b8642f93e Mon Sep 17 00:00:00 2001 From: Azareal Date: Wed, 10 Apr 2019 17:40:47 +1000 Subject: [PATCH] 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 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. --- cmd/query_gen/tables.go | 1 + common/attachments.go | 2 +- common/extend.go | 3 +- common/parser.go | 11 +++---- gen_router.go | 12 +++++--- langs/english.json | 1 + parser_test.go | 6 ++-- plugin_bbcode.go | 6 ++-- plugin_markdown.go | 4 +-- plugin_test.go | 18 +++++------ public/global.js | 13 +++++++- router_gen/main.go | 12 +++++--- templates/topic.html | 32 ++++---------------- templates/topic_alt.html | 45 ++++++++++++++-------------- templates/topic_alt_posts.html | 28 ++++++++--------- templates/topic_poll.html | 25 ++++++++++++++++ themes/cosora/public/main.css | 27 +++++++++++------ themes/nox/public/main.css | 6 ++++ themes/shadow/public/main.css | 6 ++++ themes/tempra_simple/public/main.css | 6 ++++ 20 files changed, 160 insertions(+), 104 deletions(-) create mode 100644 templates/topic_poll.html diff --git a/cmd/query_gen/tables.go b/cmd/query_gen/tables.go index f2719494..0064c832 100644 --- a/cmd/query_gen/tables.go +++ b/cmd/query_gen/tables.go @@ -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"}, diff --git a/common/attachments.go b/common/attachments.go index a8ad1f51..c3e36bdf 100644 --- a/common/attachments.go +++ b/common/attachments.go @@ -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) diff --git a/common/extend.go b/common/extend.go index fe7d49f7..ce0b0d35 100644 --- a/common/extend.go +++ b/common/extend.go @@ -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, diff --git a/common/parser.go b/common/parser.go index ad66a8d1..e2ee0776 100644 --- a/common/parser.go +++ b/common/parser.go @@ -9,13 +9,14 @@ import ( "unicode/utf8" ) +// TODO: Somehow localise these? var SpaceGap = []byte(" ") var httpProtBytes = []byte("http://") -var InvalidURL = []byte("[Invalid URL]") -var InvalidTopic = []byte("[Invalid Topic]") -var InvalidProfile = []byte("[Invalid Profile]") -var InvalidForum = []byte("[Invalid Forum]") -var unknownMedia = []byte("[Unknown Media]") +var InvalidURL = []byte("[Invalid URL]") +var InvalidTopic = []byte("[Invalid Topic]") +var InvalidProfile = []byte("[Invalid Profile]") +var InvalidForum = []byte("[Invalid Forum]") +var unknownMedia = []byte("[Unknown Media]") var URLOpen = []byte("") var bytesSinglequote = []byte("'") diff --git a/gen_router.go b/gen_router.go index 86f366ca..98a20715 100644 --- a/gen_router.go +++ b/gen_router.go @@ -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) } diff --git a/langs/english.json b/langs/english.json index 03c184d6..04a870de 100644 --- a/langs/english.json +++ b/langs/english.json @@ -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", diff --git a/parser_test.go b/parser_test.go index b79fe7a6..6edcf1b9 100644 --- a/parser_test.go +++ b/parser_test.go @@ -143,11 +143,13 @@ func TestParser(t *testing.T) { msgList.Add("//"+common.Site.URL+"\n//"+common.Site.URL, "//"+common.Site.URL+"
//"+common.Site.URL+"") msgList.Add("#tid-1", "#tid-1") + msgList.Add("#tid-0", "[Invalid Topic]") msgList.Add("https://"+url+"/#tid-1", "https://"+url+"/#tid-1") msgList.Add("#fid-1", "#fid-1") + msgList.Add("#fid-0", "[Invalid Forum]") msgList.Add("@1", "@Admin") - msgList.Add("@0", "[Invalid Profile]") - msgList.Add("@-1", "[Invalid Profile]1") + msgList.Add("@0", "[Invalid Profile]") + msgList.Add("@-1", "[Invalid Profile]1") for _, item := range msgList.Items { res := common.ParseMessage(item.Msg, 1, "forums") diff --git a/plugin_bbcode.go b/plugin_bbcode.go index 36a698a1..db2dde5c 100644 --- a/plugin_bbcode.go +++ b/plugin_bbcode.go @@ -32,9 +32,9 @@ func init() { func initBbcode(plugin *common.Plugin) error { plugin.AddHook("parse_assign", bbcodeFullParse) - bbcodeInvalidNumber = []byte("[Invalid Number]") - bbcodeNoNegative = []byte("[No Negative Numbers]") - bbcodeMissingTag = []byte("[Missing Tag]") + bbcodeInvalidNumber = []byte("[Invalid Number]") + bbcodeNoNegative = []byte("[No Negative Numbers]") + bbcodeMissingTag = []byte("[Missing Tag]") bbcodeBold = regexp.MustCompile(`(?s)\[b\](.*)\[/b\]`) bbcodeItalic = regexp.MustCompile(`(?s)\[i\](.*)\[/i\]`) diff --git a/plugin_markdown.go b/plugin_markdown.go index 9f069c8f..fe4c1d84 100644 --- a/plugin_markdown.go +++ b/plugin_markdown.go @@ -29,7 +29,7 @@ func init() { func initMarkdown(plugin *common.Plugin) error { plugin.AddHook("parse_assign", markdownParse) - markdownUnclosedElement = []byte("[Unclosed Element]") + markdownUnclosedElement = []byte("[Unclosed Element]") markdownBoldTagOpen = []byte("") markdownBoldTagClose = []byte("") @@ -63,7 +63,7 @@ func markdownParse(msg string) string { // Under Construction! func _markdownParse(msg string, n int) string { if n > markdownMaxDepth { - return "[Markdown Error: Overflowed the max depth of 20]" + return "[Markdown Error: Overflowed the max depth of 20]" } var outbytes []byte diff --git a/plugin_test.go b/plugin_test.go index 59f51e98..bb8cdf0f 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -87,7 +87,7 @@ func TestBBCodeRender(t *testing.T) { var expects string msg = "[rand][/rand]" - expects = "[Invalid Number][rand][/rand]" + expects = "[Invalid Number][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 = "[No Negative Numbers][rand]-1[/rand]" + expects = "[No Negative Numbers][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 = "[No Negative Numbers][rand]-01[/rand]" + expects = "[No Negative Numbers][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 = "[Invalid Number][rand]NaN[/rand]" + expects = "[Invalid Number][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 = "[Invalid Number][rand]Inf[/rand]" + expects = "[Invalid Number][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 = "[Invalid Number][rand]+[/rand]" + expects = "[Invalid Number][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 = "[Invalid Number][rand]1+1[/rand]" + expects = "[Invalid Number][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 != "[Invalid Number][rand]18446744073709551615[/rand]" { + if err != nil && res != "[Invalid Number][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 != "[Invalid Number][rand]170141183460469231731687303715884105727[/rand]" { + if err != nil && res != "[Invalid Number][rand]170141183460469231731687303715884105727[/rand]" { t.Error("Bad output:", "'"+res+"'") t.Error("Expected a number between 0 and 170141183460469231731687303715884105727") } diff --git a/public/global.js b/public/global.js index c33a5da7..32be662c 100644 --- a/public/global.js +++ b/public/global.js @@ -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("
"); $("#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("
"); console.log("rawData: ", rawData); console.log("series: ", data); Chartist.Pie('#poll_results_chart_' + pollID, { diff --git a/router_gen/main.go b/router_gen/main.go index 52ba0001..9d76c959 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -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) } diff --git a/templates/topic.html b/templates/topic.html index e92361c0..d7d470c5 100644 --- a/templates/topic.html +++ b/templates/topic.html @@ -1,6 +1,5 @@ {{template "header.html" . }} -
{{if gt .Page 1}} {{end}} @@ -9,9 +8,9 @@ {{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}} +
{{end}} @@ -27,29 +27,7 @@
{{if .Poll.ID}} -
-
-
- {{range .Poll.QuickOptions}} -
- - - {{.Value}} -
- {{end}} -
- - - -
-
-
-
-
-
-
+{{template "topic_poll.html" . }} {{end}}
@@ -127,4 +105,4 @@
-{{template "footer.html" . }} +{{template "footer.html" . }} \ No newline at end of file diff --git a/templates/topic_alt.html b/templates/topic_alt.html index 79e6dfa0..cc613434 100644 --- a/templates/topic_alt.html +++ b/templates/topic_alt.html @@ -6,30 +6,29 @@ {{if ne .LastPage .Page}} {{end}} +
+ -
-
-
-
-

{{.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}} - {{if not .Topic.IsClosed or .CurrentUser.Perms.CloseTopic}} - {{if .CurrentUser.Perms.EditTopic}} - - - {{end}} - {{end}} - {{end}} - {{.Topic.ViewCount}} - {{/** TODO: Inline this CSS **/}} - {{if .Topic.IsClosed}}🔒︎{{end}} -
-
+
+

{{.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}} + {{if not .Topic.IsClosed or .CurrentUser.Perms.CloseTopic}} + {{if .CurrentUser.Perms.EditTopic}} +
+ + + {{end}} + {{end}} + {{end}} + {{.Topic.ViewCount}} + {{/** TODO: Inline this CSS **/}} + {{if .Topic.IsClosed}}🔒︎{{end}} +
@@ -56,7 +55,9 @@
-
+
+
{{lang "topic.poll_no_results"}}
+
{{end}} diff --git a/templates/topic_alt_posts.html b/templates/topic_alt_posts.html index c805c7dd..b43a088a 100644 --- a/templates/topic_alt_posts.html +++ b/templates/topic_alt_posts.html @@ -11,20 +11,20 @@ {{if $.CurrentUser.Perms.EditReply}} {{if .Attachments}}
- {{range .Attachments}} -
- {{if .Image}}{{end}} - {{.Path}} - - -
- {{end}} -
- {{if $.CurrentUser.Perms.UploadFiles}} - - {{end}} - -
+ {{range .Attachments}} +
+ {{if .Image}}{{end}} + {{.Path}} + + +
+ {{end}} +
+ {{if $.CurrentUser.Perms.UploadFiles}} + + {{end}} + +
{{end}} {{end}}{{end}} diff --git a/templates/topic_poll.html b/templates/topic_poll.html new file mode 100644 index 00000000..2581801f --- /dev/null +++ b/templates/topic_poll.html @@ -0,0 +1,25 @@ +
+
+
+ {{range .Poll.QuickOptions}} +
+ + + {{.Value}} +
+ {{end}} +
+ + + +
+
+
+
+
{{lang "topic.poll_no_results"}}
+
+
+
+
\ No newline at end of file diff --git a/themes/cosora/public/main.css b/themes/cosora/public/main.css index 0073b578..209e3d2e 100644 --- a/themes/cosora/public/main.css +++ b/themes/cosora/public/main.css @@ -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; diff --git a/themes/nox/public/main.css b/themes/nox/public/main.css index a30f4fb1..7883a71d 100644 --- a/themes/nox/public/main.css +++ b/themes/nox/public/main.css @@ -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; diff --git a/themes/shadow/public/main.css b/themes/shadow/public/main.css index ca497f5d..cbd921b8 100644 --- a/themes/shadow/public/main.css +++ b/themes/shadow/public/main.css @@ -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; diff --git a/themes/tempra_simple/public/main.css b/themes/tempra_simple/public/main.css index 41b895f8..6d1b236c 100644 --- a/themes/tempra_simple/public/main.css +++ b/themes/tempra_simple/public/main.css @@ -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; }