Compare commits

..

7 Commits

Author SHA1 Message Date
httpjamesm 6f86cbce6e feat: update version num to 1.3 2022-12-28 22:55:42 -05:00
httpjamesm 1d2e98e4c1 style: add margin between comments and divider 2022-12-28 22:55:30 -05:00
httpjamesm 599d23544b feat: unify comments finder, show post comments
style: show post notices in a clean layout
2022-12-28 22:54:13 -05:00
httpjamesm 84ba0886cd feat: show answer comments under collapsible 2022-12-28 22:48:02 -05:00
httpjamesm 5bd9ce484f fix: escape code blocks to prevent HTML injection 2022-12-28 22:18:18 -05:00
httpjamesm 8f9091fb2a docs: add chroma to attribution 2022-12-28 19:20:58 -05:00
httpjamesm 1b1120d924 docs: attribution with licenses 2022-12-28 19:19:53 -05:00
8 changed files with 118 additions and 13 deletions
+9 -2
View File
@@ -48,7 +48,11 @@ ${instanceURL}/questions/43743250/using-libsodium-xchacha20-poly1305-for-large-f
You can easily convert StackOverflow URLs to AnonymousOverflow ones by adding the following code as a bookmark in your web browser: You can easily convert StackOverflow URLs to AnonymousOverflow ones by adding the following code as a bookmark in your web browser:
```js ```js
javascript:(function() {window.location=window.location.toString().replace(/stackoverflow\.com/,'code.whatever.social');})() javascript: (function () {
window.location = window.location
.toString()
.replace(/stackoverflow\.com/, "code.whatever.social");
})();
``` ```
Replace `code.whatever.social` with the domain name of the instance you're using if needed. Replace `code.whatever.social` with the domain name of the instance you're using if needed.
@@ -57,7 +61,6 @@ You can run this bookmarklet on any StackOverflow page to view it anonymously.
Thanks to [Manav from ente.io](https://ente.io/about) for the handy tool. Thanks to [Manav from ente.io](https://ente.io/about) for the handy tool.
## How to deploy ## How to deploy
AnonymousOverflow uses Docker for deployment. AnonymousOverflow uses Docker for deployment.
@@ -71,3 +74,7 @@ Run `docker compose up -d` to build and start the container.
## Attribution ## Attribution
- Icons provided by [heroicons](https://heroicons.com) under the [MIT License](https://choosealicense.com/licenses/mit/) - Icons provided by [heroicons](https://heroicons.com) under the [MIT License](https://choosealicense.com/licenses/mit/)
- [Gin](https://github.com/gin-gonic/gin) under the [MIT License](https://github.com/gin-gonic/gin/blob/master/LICENSE)
- [goquery](https://github.com/PuerkitoBio/goquery) under the [BSD 3-Clause License](https://github.com/PuerkitoBio/goquery/blob/master/LICENSE)
- [resty](https://github.com/go-resty/resty) under the [MIT License](https://github.com/go-resty/resty/blob/master/LICENSE)
- [Chroma](https://github.com/alecthomas/chroma) under the [MIT License](https://github.com/alecthomas/chroma/blob/master/COPYING)
+1 -1
View File
@@ -1,3 +1,3 @@
package config package config
var Version = "1.2" var Version = "1.3"
+4
View File
@@ -47,3 +47,7 @@ html {
border-radius: 50%; border-radius: 50%;
padding: .25rem; padding: .25rem;
} }
details {
cursor: pointer;
}
+35 -5
View File
@@ -31,7 +31,7 @@ body {
code { code {
background-color: var(--code-bg); background-color: var(--code-bg);
padding: .15rem; padding: 0.15rem;
border-radius: 5px; border-radius: 5px;
color: white; color: white;
} }
@@ -45,15 +45,17 @@ pre {
line-height: 1.35; line-height: 1.35;
} }
.timestamp { .timestamp {
color: var(--muted-text-color); color: var(--muted-text-color);
font-size: 0.8rem; font-size: 0.8rem;
} }
.answer-divider { .post-divider, .answer-divider {
margin-top: 3rem; margin-top: 3rem;
margin-bottom: 3rem; margin-bottom: 3rem;
}
.answer-divider {
border: 0; border: 0;
height: 1px; height: 1px;
background-color: var(--divider-color); background-color: var(--divider-color);
@@ -85,10 +87,10 @@ img {
.answer-author { .answer-author {
width: fit-content; width: fit-content;
background-color: var(--meta-bg); background-color: var(--meta-bg);
padding: .5rem; padding: 0.5rem;
border-radius: 5px; border-radius: 5px;
text-align: right; text-align: right;
font-size: .8rem; font-size: 0.8rem;
} }
.logo-link { .logo-link {
@@ -100,6 +102,34 @@ img {
height: 2rem; height: 2rem;
} }
.comments-parent {
display: flex;
flex-direction: column;
gap: 1rem;
margin-top: 1rem;
}
.comment-parent {
cursor: text;
}
.comment-body {
font-size: 0.95rem;
}
.comment-author {
color: var(--muted-text-color);
font-size: 0.8rem;
}
.s-notice {
background-color: var(--meta-bg);
padding: 1rem;
border-radius: 5px;
color: var(--text-color);
margin-bottom: 1rem;
}
@media only screen and (max-width: 800px) { @media only screen and (max-width: 800px) {
body { body {
padding-left: 1rem; padding-left: 1rem;
+7 -1
View File
@@ -42,6 +42,8 @@ func ViewQuestion(c *gin.Context) {
questionText := questionTextParent.Children().First().Text() questionText := questionTextParent.Children().First().Text()
questionPostLayout := doc.Find("div.post-layout").First()
questionBodyParent := doc.Find("div.s-prose") questionBodyParent := doc.Find("div.s-prose")
questionBodyParentHTML, err := questionBodyParent.Html() questionBodyParentHTML, err := questionBodyParent.Html()
@@ -49,6 +51,8 @@ func ViewQuestion(c *gin.Context) {
panic(err) panic(err)
} }
questionBodyParentHTML = utils.FindAndReturnComments(questionBodyParentHTML, questionPostLayout)
// parse any code blocks and highlight them // parse any code blocks and highlight them
answerCodeBlocks := questionCodeBlockRegex.FindAllString(questionBodyParentHTML, -1) answerCodeBlocks := questionCodeBlockRegex.FindAllString(questionBodyParentHTML, -1)
for _, codeBlock := range answerCodeBlocks { for _, codeBlock := range answerCodeBlocks {
@@ -152,7 +156,7 @@ func ViewQuestion(c *gin.Context) {
}) })
// append <div class="answer-author">Answered %s by %s</div> to the bottom of the answer // append <div class="answer-author">Answered %s by %s</div> to the bottom of the answer
answerBodyHTML += fmt.Sprintf(`<div class="answer-author-parent"><div class="answer-author">Answered at %s by <a href="https://stackoverflow.com/%s" target="_blank" rel="noopener noreferrer">%s</a></div></div>`, answerTimestamp, answerAuthorURL, answerAuthorName) answerBodyHTML += fmt.Sprintf(`<div class="answer-author-parent"><div class="answer-author">Answered %s by <a href="https://stackoverflow.com/%s" target="_blank" rel="noopener noreferrer">%s</a></div></div>`, answerTimestamp, answerAuthorURL, answerAuthorName)
// parse any code blocks and highlight them // parse any code blocks and highlight them
answerCodeBlocks := codeBlockRegex.FindAllString(answerBodyHTML, -1) answerCodeBlocks := codeBlockRegex.FindAllString(answerBodyHTML, -1)
@@ -166,6 +170,8 @@ func ViewQuestion(c *gin.Context) {
answerBodyHTML = strings.Replace(answerBodyHTML, codeBlock, highlightedCodeBlock, 1) answerBodyHTML = strings.Replace(answerBodyHTML, codeBlock, highlightedCodeBlock, 1)
} }
answerBodyHTML = utils.FindAndReturnComments(answerBodyHTML, postLayout)
answers = append(answers, template.HTML(answerBodyHTML)) answers = append(answers, template.HTML(answerBodyHTML))
}) })
+58
View File
@@ -0,0 +1,58 @@
package utils
import (
"fmt"
"strings"
"github.com/PuerkitoBio/goquery"
)
func FindAndReturnComments(inHtml string, postLayout *goquery.Selection) (outHtml string) {
outHtml = inHtml
comments := []string{}
commentsComponent := postLayout.Find("div.js-post-comments-component")
commentsList := commentsComponent.Find("div.comments")
commentsList2 := commentsList.Find("ul.comments-list")
allComments := commentsList2.Find("li.comment")
allComments.Each(func(i int, s *goquery.Selection) {
commentText := s.Find("div.comment-text")
commentBody := commentText.Find("div.comment-body")
commentCopy, err := commentBody.Find("span.comment-copy").Html()
if err != nil {
return
}
commentAuthorURL := ""
commentAuthor := commentBody.Find("span.comment-user")
if commentAuthor.Length() == 0 {
commentAuthor = commentBody.Find("a.comment-user")
if commentAuthor.Length() == 0 {
return
}
commentAuthorURL = commentAuthor.AttrOr("href", "")
}
commentTimestamp := commentBody.Find("span.relativetime-clean").Text()
comment := fmt.Sprintf(`<div class="comment-parent"><div class="comment"><div class="comment-body">%s</div><div class="comment-author">Commented %s by <a href="https://stackoverflow.com%s" target="_blank" rel="noopener noreferrer">%s</a>.</div></div></div>`, commentCopy, commentTimestamp, commentAuthorURL, commentAuthor.Text())
comments = append(comments, comment)
})
if len(comments) > 0 {
outHtml = inHtml + fmt.Sprintf(`<details class="comments"><summary>Show <b>%d comments</b></summary><div class="comments-parent">%s</div></details>`, len(comments), strings.Join(comments, ""))
}
return
}
+1 -1
View File
@@ -17,7 +17,7 @@ var plainFormattedCodeRegex = regexp.MustCompile(`(?s)<pre tabindex="0" class="c
func HighlightSyntaxViaContent(content string) (htmlOut string) { func HighlightSyntaxViaContent(content string) (htmlOut string) {
content = html.UnescapeString(content) content = html.UnescapeString(content)
fallbackOut := content fallbackOut := html.EscapeString(content)
// identify the language // identify the language
lexer := lexers.Analyse(content) lexer := lexers.Analyse(content)
+1 -1
View File
@@ -47,7 +47,7 @@
</div> </div>
<div class="card-body">{{ .body }}</div> <div class="card-body">{{ .body }}</div>
</div> </div>
<hr /> <hr class="post-divider" />
<h2>Answers</h2> <h2>Answers</h2>
{{ range $answer := .answers }} {{ range $answer := .answers }}
<div class="answer">{{ $answer }}</div> <div class="answer">{{ $answer }}</div>