mirror of
https://github.com/httpjamesm/AnonymousOverflow.git
synced 2024-12-06 19:16:43 +01:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f86cbce6e | |||
| 1d2e98e4c1 | |||
| 599d23544b | |||
| 84ba0886cd | |||
| 5bd9ce484f | |||
| 8f9091fb2a | |||
| 1b1120d924 |
@@ -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
@@ -1,3 +1,3 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
var Version = "1.2"
|
var Version = "1.3"
|
||||||
|
|||||||
@@ -47,3 +47,7 @@ html {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
padding: .25rem;
|
padding: .25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
details {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
+37
-7
@@ -8,7 +8,7 @@ body {
|
|||||||
background-color: var(--main-bg);
|
background-color: var(--main-bg);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
@@ -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,9 +102,37 @@ 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;
|
||||||
padding-right: 1rem;
|
padding-right: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user