diff --git a/.gitignore b/.gitignore
index c9a2389..3d7be86 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
mlmym
+VERSION
*.toml
*.txt
diff --git a/Dockerfile b/Dockerfile
index 1bd6c58..9b9ab73 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,6 +4,7 @@ WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . ./
+RUN git describe --tag > VERSION
RUN go build -v -o mlmym
FROM debian:bullseye-slim
@@ -14,4 +15,5 @@ RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -
COPY --from=builder /app/mlmym /app/mlmym
COPY --from=builder /app/templates /app/templates
COPY --from=builder /app/public /app/public
+COPY --from=builder /app/VERSION /app/VERSION
CMD ["./mlmym", "--addr", "0.0.0.0:8080"]
diff --git a/Makefile b/Makefile
index 0ac9db1..1b88d82 100644
--- a/Makefile
+++ b/Makefile
@@ -1,17 +1,18 @@
-.PHONY: dev reload serve style
+.PHONY: dev reload serve VERSION
-all:
- $(MAKE) -j3 --no-print-directory dev
+all: mlmym
-dev: reload serve style
+mlmym: VERSION
+ go build -v -o mlmym
+
+dev:
+ $(MAKE) -j2 --no-print-directory reload serve
reload:
- #websocketd --port=8080 watchexec -w public echo reload &>/dev/null
- websocketd --loglevel=fatal --port=8009 watchexec --no-vcs-ignore -e html,css,js -d 500 -w public 'echo "$$WATCHEXEC_WRITTEN_PATH"'
+ websocketd --loglevel=fatal --port=8009 watchexec --no-vcs-ignore -e html,css,js 'echo "$$WATCHEXEC_WRITTEN_PATH"'
-serve:
- #python -m http.server --directory ./public 8081 &>/dev/null
- DEBUG=true watchexec -e go -r "go run . --addr 0.0.0.0:8008 -w"
+VERSION:
+ git describe --tag > $@
-style:
- npm run watchcss > /dev/null 2>&1
+serve: VERSION
+ DEBUG=true watchexec --no-vcs-ignore -e go -r "go run . --addr 0.0.0.0:8008 -w"
diff --git a/README.md b/README.md
index ee99f9e..c2bde67 100644
--- a/README.md
+++ b/README.md
@@ -3,14 +3,23 @@ a familiar desktop experience for [lemmy](https://join-lemmy.org).

-### deployment
+## deployment
```bash
docker run -it -p "8080:8080" ghcr.io/rystaf/mlmym:latest
```
-### config
+## config
Set the environment variable `LEMMY_DOMAIN` to run in single instance mode
```bash
docker run -it -e LEMMY_DOMAIN='lemmydomain.com' -p "8080:8080" ghcr.io/rystaf/mlmym:latest
```
+#### default user settings
+| environment variable | default |
+| -------------------- | ------- |
+| DARK | false |
+| HIDE_THUMBNAILS | false |
+| LISTING | All |
+| SORT | Hot |
+| COMMENT_SORT | Hot |
+
diff --git a/main.go b/main.go
index a7aee4f..95e0f3d 100644
--- a/main.go
+++ b/main.go
@@ -14,6 +14,7 @@ import (
"github.com/yuin/goldmark/extension"
)
+var version string
var watch = flag.Bool("w", false, "watch for file changes")
var addr = flag.String("addr", ":80", "http service address")
var md goldmark.Markdown
@@ -55,7 +56,7 @@ func init() {
))
templates = make(map[string]*template.Template)
if !*watch {
- for _, name := range []string{"index.html", "login.html", "frontpage.html", "root.html", "settings.html", "xhr.html"} {
+ for _, name := range []string{"index.html", "login.html", "frontpage.html", "root.html", "settings.html", "xhr.html", "create_comment.html"} {
t := template.New(name).Funcs(funcMap)
glob, err := t.ParseGlob("templates/*")
if err != nil {
@@ -68,6 +69,9 @@ func init() {
if os.Getenv("DEBUG") != "" {
test()
}
+ if data, err := os.ReadFile("VERSION"); err == nil {
+ version = string(data)
+ }
}
func test() {
links := [][]string{
@@ -80,6 +84,7 @@ func test() {
[]string{"https://lemmy.world/u/dude", "/lemmy.local/u/dude@lemmy.world", "/u/dude@lemmy.world"},
[]string{"https://lemmy.world/u/dude@lemmy.world", "/lemmy.local/u/dude@lemmy.world", "/u/dude@lemmy.world"},
[]string{"https://lemmy.world/post/123", "/lemmy.local/post/123@lemmy.world", "/post/123@lemmy.world"},
+ []string{"https://lemmy.world/post/123#123", "https://lemmy.world/post/123#123", "https://lemmy.world/post/123#123"},
[]string{"/post/123", "/lemmy.local/post/123", "/post/123"},
[]string{"/comment/123", "/lemmy.local/comment/123", "/comment/123"},
[]string{"https://lemmy.local/comment/123", "/lemmy.local/comment/123", "/comment/123"},
diff --git a/public/noscript.css b/public/noscript.css
new file mode 100644
index 0000000..8b24e2a
--- /dev/null
+++ b/public/noscript.css
@@ -0,0 +1,17 @@
+.scripting,
+.expando-button,
+.minimize,
+#showimages,
+#lmc,
+.hidechildren {
+ display: none !important;
+}
+.post .expando .image img {
+ visibility: visible;
+}
+div.pager {
+ display: block;
+}
+.savecomment input[type=file] {
+ display: inline-block;
+}
diff --git a/public/style.css b/public/style.css
index 4cef8b7..7522f61 100644
--- a/public/style.css
+++ b/public/style.css
@@ -219,6 +219,27 @@ summary {
font-size: 10px;
margin-bottom: 6px;
}
+.preview h3 {
+ background-color: #f0f3fc;
+ border: 0px solid #e6e6e6;
+ border-bottom-width: 1px;
+ color: black;
+ margin: 0px;
+ padding: 10px;
+ font-size: 14px;
+}
+.dark .preview h3 {
+ background-color: #333;
+ border-color: #333;
+ color: #ccc;
+}
+.preview .comment {
+ margin-top: 5px;
+ padding: 0px;
+}
+.preview .comment .content {
+ padding: 5px 10px;
+}
.meta a, .activity .meta a {
color: #369;
text-decoration: none;
@@ -262,6 +283,7 @@ summary {
}
form.savecomment {
margin: 0px 0px 10px 0px;
+ width: 500px;
}
.comment > .children > form.savecomment {
margin: 0px 0px 10px 20px;
@@ -270,9 +292,34 @@ form.savecomment {
margin: 5px 0px 10px 15px;
}
.savecomment textarea {
- width: 500px;
+ margin: 5px 0px;
+ width: 100%;
height: 100px;
}
+
+.savecomment .upload label div {
+ display: inline-block;
+ border: 1px solid #ccc;
+ height: 20px;
+ line-height: 20px;
+ width: 32px;
+ position: relative;
+ background-color: #999;
+ color: #000;
+ text-align: center;
+ cursor: pointer;
+}
+.savecomment .upload input {
+ display: none;
+}
+.savecomment .right {
+ float:right;
+}
+.savecomment .right a {
+ line-height: 28px;
+ font-size: 10px;
+}
+
.comment .meta a.minimize {
color: #369;
font-size: 10px;
@@ -956,11 +1003,11 @@ nav .right a.mailbox {
top: 4px;
color: gray;
}
-nav .right a, .right input[type=submit] {
+nav .right a, nav .right input[type=submit] {
color: #369;
text-decoration: none;
}
-.dark nav .right a, .dark .right input[type=submit]{
+.dark nav .right a, .dark nav .right input[type=submit]{
color: #dadada;
}
nav .right form, .comment form, form.link-btn {
@@ -1057,9 +1104,13 @@ form.create input[type=file], form.create select {
font-size: 13px;
margin: 10px;
}
+.preferences div:last-child label {
+ text-align: left;
+ font-size: 10px;
+}
.preferences label{
display: inline-block;
- width: 130px;
+ width: 150px;
margin-right: 5px;
text-align: right;
diff --git a/public/utils.js b/public/utils.js
index 04c8a92..df8c22a 100644
--- a/public/utils.js
+++ b/public/utils.js
@@ -10,8 +10,6 @@ function request(url, params, callback, errorcallback = function(){}) {
var method = "GET"
if (params) method = "POST"
xmlHttp.open(method, url, true);
- if (method = "POST")
- xmlHttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xmlHttp.send(params);
}
function postClick(e) {
@@ -34,25 +32,31 @@ function postClick(e) {
}
}
}
+function uptil (el, f) {
+ if (el) return f(el) ? el : uptil(el.parentNode, f)
+}
function commentClick(e) {
e = e || window.event;
var targ = e.currentTarget || e.srcElement || e;
if (targ.nodeType == 3) targ = targ.parentNode;
if (e.target.name=="submit") {
e.preventDefault()
- var form = e.target.parentNode
+ var form = uptil(e.target, function(el){ return el.tagName == "FORM" })
if (form) {
data = new FormData(form)
+ data.set(e.target.name, e.target.value)
+ data.set("xhr", 1)
if (("c"+data.get("commentid")) == targ.id) {
-
+ targ.action = form.action
+ if (e.target.value == "preview") {
+ targ = form
+ }
+ console.log("ok")
} else if (("c"+data.get("parentid")) == targ.id) {
targ = form
} else { return }
- params = new URLSearchParams(data).toString()
- params += "&" + e.target.name + "=" + e.target.value
- params += "&xhr=1"
e.target.disabled = "disabled"
- request(targ.target || "", params,
+ request(targ.action || "", data,
function(res){
targ.outerHTML = res
setup()
@@ -217,11 +221,10 @@ function formSubmit(e) {
var targ = e.currentTarget || e.srcElement || e;
e.preventDefault()
var data = new FormData(targ)
- params = new URLSearchParams(data).toString()
- params += "&" + e.submitter.name + "=" + e.submitter.value
- params += "&xhr=1"
+ data.set(e.submitter.name, e.submitter.value)
+ data.set("xhr", "1")
e.submitter.disabled = "disabled"
- request(targ.target, params,
+ request(targ.target, data,
function(res){
if (data.get("op") == "read_post") {
document.getElementById("p"+data.get("postid")).remove()
@@ -245,19 +248,25 @@ function toggleMyCommunities(e) {
return false
}
mycommunities.className = "open"
- mycommunities.innerHTML = "
loading
"
- request(e.target.href + "&xhr=1", "", function(res) {
- mycommunities.innerHTML = 'view all »'
- mycommunities.innerHTML += res
- }, function() {
- mycommunities.className = ""
- })
+ if (mycommunities.innerHTML == "") {
+ mycommunities.innerHTML = "
loading
"
+ request(e.target.href + "&xhr=1", "", function(res) {
+ mycommunities.innerHTML = '
view all »'
+ mycommunities.innerHTML += res
+ }, function() {
+ mycommunities.className = ""
+ })
+ }
return false
}
function openSettings(e) {
e.preventDefault()
var settings = document.getElementById("settingspopup")
+ if (settings.className == "open") {
+ settings.className = ""
+ return false
+ }
settings.className = "open"
request(e.target.href + "?xhr=1", "", function(res) {
settings.innerHTML = res
@@ -287,8 +296,7 @@ function saveSettings(e) {
var targ = e.currentTarget || e.srcElement || e;
var data = new FormData(targ)
e.preventDefault()
- var params = new URLSearchParams(data).toString()
- request(targ.target, params, function(res) {
+ request(targ.target, data, function(res) {
["endlessScrolling", "autoLoad"].map(function(x) {
localStorage.setItem(x, data.get(x)=="on")
})
@@ -343,6 +351,16 @@ function toggleImages(open) {
}
}
+function insertImg(e) {
+ e = e || window.event;
+ var form = uptil(e.target, function(el){ return el.tagName == "FORM" })
+ form.querySelector("input[value=preview]").click()
+ var inputs = form.getElementsByTagName("input")
+ for (var i = 0; i < inputs.length; i++) {
+ inputs[i].disabled = "disabled"
+ }
+}
+
function setup() {
if (showimages = document.getElementById("se")) {
showimages.addEventListener("click", showImages)
@@ -363,6 +381,10 @@ function setup() {
}
lmc.addEventListener("click", loadMoreComments)
}
+ var imgUpload = document.getElementsByClassName("imgupload")
+ for (var i = 0; i < imgUpload.length; i++) {
+ imgUpload[i].addEventListener("change", insertImg)
+ }
var posts = document.getElementsByClassName("post")
for (var i = 0; i < posts.length; i++) {
posts[i].addEventListener("click", postClick)
diff --git a/public/ws.js b/public/ws.js
new file mode 100644
index 0000000..08ac7c3
--- /dev/null
+++ b/public/ws.js
@@ -0,0 +1,33 @@
+var ok = false
+var t = 800
+var ws
+var prot = location.protocol == 'https:' ? "wss://":"ws://"
+let port = ":8009"
+
+function start(){
+ let url = prot + document.location.hostname + port + document.location.pathname + document.location.search;
+ console.log('connecting to ', url);
+ ws = new WebSocket(url);
+ ws.onopen = function(){
+ console.log("open");
+ t = 800
+ }
+ ws.onmessage = function(msg){
+ console.log("reload:", msg.data)
+ if (msg.data == "") {
+ return
+ }
+ window.location.reload()
+ }
+ ws.onclose = function(){
+ console.log("close");
+ setTimeout(function(){
+ //start()
+ if (t < 10 * 1000) t += 200
+ }, t);
+ };
+}
+console.log("ws");
+if (typeof WebSocket != 'undefined') {
+ start()
+}
diff --git a/routes.go b/routes.go
index eea125b..d72d653 100644
--- a/routes.go
+++ b/routes.go
@@ -133,6 +133,8 @@ var funcMap = template.FuncMap{
var buf bytes.Buffer
re := regexp.MustCompile(`\s---\s`)
body = re.ReplaceAllString(body, "\n***\n")
+ // community bangs
+ body = RegReplace(body, `([^\[])!([a-zA-Z0-9_]+)@([a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)+)`, `$1[!$2@$3](/c/$2@$3)`)
if err := md.Convert([]byte(body), &buf); err != nil {
fmt.Println(err)
return template.HTML(body)
@@ -150,7 +152,7 @@ var funcMap = template.FuncMap{
return body
}
text := html2text.HTML2TextWithOptions(buf.String(), html2text.WithLinksInnerText())
- re := regexp.MustCompile(`\
`)
+ re := regexp.MustCompile(`\<(https?:\/\/|mailto)(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)\>`)
return re.ReplaceAllString(text, "")
},
"contains": strings.Contains,
@@ -164,10 +166,8 @@ var funcMap = template.FuncMap{
func LemmyLinkRewrite(input string, host string, lemmy_domain string) (body string) {
body = input
- // community bangs
- body = RegReplace(body, `!([a-zA-Z0-9]+)@([a-zA-Z0-9\.\-]+)([ \n\r]+|<\/p>)`, `!$1@$2 `)
// localize community and user links
- body = RegReplace(body, `href="https:\/\/([a-zA-Z0-9\.\-]+)\/((c|u|comment|post)\/.*?)"`, `href="/$2@$1"`)
+ body = RegReplace(body, `href="https:\/\/([a-zA-Z0-9\.\-]+)\/((c|u|comment|post)\/[^#\?]*?)"`, `href="/$2@$1"`)
// remove extra instance tag
body = RegReplace(body, `href="(https:\/)?(\/[a-zA-Z0-9\.\-]+)?\/((c|u)\/[a-zA-Z0-9]+@[a-zA-Z0-9\.\-]+)@([a-zA-Z0-9\.\-]+)"`, `href="/$3"`)
if lemmy_domain == "" {
@@ -180,9 +180,21 @@ func LemmyLinkRewrite(input string, host string, lemmy_domain string) (body stri
body = RegReplace(body, `href="https:\/\/`+lemmy_domain+`\/(c\/[a-zA-Z0-9]+"|(c|u|post|comment)\/(.*?)")`, `href="/$1`)
body = RegReplace(body, `href="(.*)@`+lemmy_domain+`"`, `href="$1"`)
}
- // remove redundant instance tag
- re := regexp.MustCompile(`href="\/([a-zA-Z0-9\.\-]+)\/(c|u|post|comment)\/(.*?)@(.*?)"`)
+
+ re := regexp.MustCompile(`href="\/?([a-zA-Z0-9\.\-]*)\/(c|u|post|comment)\/(.*?)@(.*?)"`)
+ // assume "old." subdomain is mlmym and remove
matches := re.FindAllStringSubmatch(body, -1)
+ for _, match := range matches {
+ if match[4][0:4] == "old." {
+ s := 1
+ if match[1] == "" {
+ s += 1
+ }
+ body = strings.Replace(body, match[0], `href="/`+strings.Join(match[s:4], "/")+"@"+match[4][4:]+`"`, -1)
+ }
+ }
+ // remove redundant instance tag
+ matches = re.FindAllStringSubmatch(body, -1)
for _, match := range matches {
if match[1] == match[4] {
body = strings.Replace(body, match[0], `href="/`+strings.Join(match[1:4], "/")+`"`, -1)
@@ -196,11 +208,23 @@ func RegReplace(input string, match string, replace string) string {
return re.ReplaceAllString(input, replace)
}
+func getenv(key, fallback string) string {
+ value := os.Getenv(key)
+ if len(value) == 0 {
+ return fallback
+ }
+ return value
+}
+
func Initialize(Host string, r *http.Request) (State, error) {
state := State{
- Host: Host,
- Page: 1,
- Status: http.StatusOK,
+ Host: Host,
+ Page: 1,
+ Status: http.StatusOK,
+ Version: version,
+ }
+ if watch != nil {
+ state.Watch = *watch
}
lemmyDomain := os.Getenv("LEMMY_DOMAIN")
if lemmyDomain != "" {
@@ -236,18 +260,27 @@ func Initialize(Host string, r *http.Request) (State, error) {
state.Listing = getCookie(r, "DefaultListingType")
state.Sort = getCookie(r, "DefaultSortType")
state.CommentSort = getCookie(r, "DefaultCommentSortType")
- state.Dark = getCookie(r, "Dark") != ""
+ if dark := getCookie(r, "Dark"); dark != "" {
+ state.Dark = dark != "0"
+ } else {
+ state.Dark = os.Getenv("DARK") != ""
+ }
state.ShowNSFW = getCookie(r, "ShowNSFW") != ""
state.HideInstanceNames = getCookie(r, "HideInstanceNames") != ""
+ if hide := getCookie(r, "HideThumbnails"); hide != "" {
+ state.HideThumbnails = hide != "0"
+ } else {
+ state.HideThumbnails = os.Getenv("HIDE_THUMBNAILS") != ""
+ }
state.ParseQuery(r.URL.RawQuery)
if state.Sort == "" {
- state.Sort = "Hot"
+ state.Sort = getenv("SORT", "Hot")
}
if state.CommentSort == "" {
- state.CommentSort = "Hot"
+ state.CommentSort = getenv("COMMENT_SORT", "Hot")
}
if state.Listing == "" || state.Session == nil && state.Listing == "Subscribed" {
- state.Listing = "All"
+ state.Listing = getenv("LISTING", "All")
}
return state, nil
}
@@ -491,6 +524,9 @@ func GetPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
state.Op = "edit_post"
state.GetSite()
}
+ if len(m["content"]) > 0 {
+ state.Content = m["content"][0]
+ }
postid, _ := strconv.Atoi(ps.ByName("postid"))
state.GetPost(postid)
state.GetComments()
@@ -535,6 +571,9 @@ func GetComment(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
if len(m["edit"]) > 0 {
state.Op = "edit"
}
+ if r.Method == "POST" && len(m["content"]) > 0 {
+ state.Content = m["content"][0]
+ }
if len(m["source"]) > 0 {
state.Op = "source"
}
@@ -544,6 +583,10 @@ func GetComment(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
}
commentid, _ := strconv.Atoi(ps.ByName("commentid"))
state.GetComment(commentid)
+ if state.XHR && len(m["content"]) > 0 {
+ Render(w, "create_comment.html", state)
+ return
+ }
state.GetPost(state.PostID)
Render(w, "index.html", state)
}
@@ -661,6 +704,7 @@ func Settings(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
Render(w, "index.html", state)
return
}
+ state.GetSite()
switch r.Method {
case "POST":
for _, name := range []string{"DefaultSortType", "DefaultListingType", "DefaultCommentSortType"} {
@@ -671,8 +715,7 @@ func Settings(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
setCookie(w, "", "Dark", "1")
state.Dark = true
} else {
- deleteCookie(w, state.Host, "Dark")
- deleteCookie(w, "", "Dark")
+ setCookie(w, "", "Dark", "0")
state.Dark = false
}
if r.FormValue("shownsfw") != "" {
@@ -690,6 +733,13 @@ func Settings(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
deleteCookie(w, "", "HideInstanceNames")
state.HideInstanceNames = false
}
+ if r.FormValue("hideThumbnails") != "" {
+ setCookie(w, "", "HideThumbnails", "1")
+ state.HideInstanceNames = true
+ } else {
+ setCookie(w, "", "HideThumbnails", "0")
+ state.HideInstanceNames = false
+ }
state.Listing = r.FormValue("DefaultListingType")
state.Sort = r.FormValue("DefaultSortType")
state.CommentSort = r.FormValue("DefaultCommentSortType")
@@ -1185,9 +1235,20 @@ func UserOp(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
parentid, _ := strconv.Atoi(r.FormValue("parentid"))
state.GetComment(parentid)
}
+ content := r.FormValue("content")
+ file, handler, err := r.FormFile("file")
+ if err == nil {
+ pres, err := state.UploadImage(file, handler)
+ if err != nil {
+ state.Error = err
+ Render(w, "index.html", state)
+ return
+ }
+ content += ("")
+ }
if r.FormValue("submit") == "save" {
createComment := types.CreateComment{
- Content: r.FormValue("content"),
+ Content: content,
PostID: state.PostID,
}
if state.CommentID > 0 {
@@ -1209,6 +1270,22 @@ func UserOp(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
} else {
fmt.Println(err)
}
+ } else if r.FormValue("submit") == "preview" {
+ q := r.URL.Query()
+ q.Set("content", content)
+ q.Set("reply", "")
+ if r.FormValue("xhr") != "" {
+ q.Set("xhr", "1")
+ }
+ r.URL.RawQuery = q.Encode()
+ if ps.ByName("postid") != "" {
+ GetPost(w, r, ps)
+ return
+ }
+ if ps.ByName("commentid") != "" {
+ GetComment(w, r, ps)
+ return
+ }
} else if r.FormValue("xhr") != "" {
w.Write([]byte{})
return
@@ -1218,10 +1295,23 @@ func UserOp(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
}
case "edit_comment":
commentid, _ := strconv.Atoi(r.FormValue("commentid"))
+ q := r.URL.Query()
+ content := r.FormValue("content")
+ file, handler, err := r.FormFile("file")
+ if err == nil {
+ pres, err := state.UploadImage(file, handler)
+ if err != nil {
+ state.Error = err
+ Render(w, "index.html", state)
+ return
+ }
+ content += ("")
+ }
+
if r.FormValue("submit") == "save" {
resp, err := state.Client.EditComment(context.Background(), types.EditComment{
CommentID: commentid,
- Content: types.NewOptional(r.FormValue("content")),
+ Content: types.NewOptional(content),
})
if err != nil {
fmt.Println(err)
@@ -1230,6 +1320,29 @@ func UserOp(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
r.URL.Fragment = "c" + commentid
r.URL.RawQuery = ""
}
+ } else if r.FormValue("submit") == "preview" {
+ q.Set("content", content)
+ q.Set("edit", "")
+ if r.FormValue("xhr") != "" {
+ q.Set("xhr", "1")
+ }
+ r.URL.RawQuery = q.Encode()
+ if ps.ByName("commentid") != "" {
+ GetComment(w, r, ps)
+ return
+ }
+ } else if r.FormValue("submit") == "cancel" {
+ if ps.ByName("commentid") != "" {
+ if r.FormValue("xhr") != "" {
+ q.Set("xhr", "1")
+ }
+ r.URL.RawQuery = q.Encode()
+ GetComment(w, r, ps)
+ return
+ }
+ } else if r.FormValue("xhr") != "" {
+ w.Write([]byte{})
+ return
}
if r.FormValue("xhr") != "" {
state.XHR = true
diff --git a/state.go b/state.go
index 630a9e1..1e2085a 100644
--- a/state.go
+++ b/state.go
@@ -59,11 +59,14 @@ type Post struct {
}
type Session struct {
- UserName string
- UserID int
+ UserName string
+ UserID int
+ Communities []types.CommunityView
}
type State struct {
+ Watch bool
+ Version string
Client *lemmy.Client
HTTPClient *http.Client
Session *Session
@@ -95,11 +98,13 @@ type State struct {
Op string
Site *types.GetSiteResponse
Query string
+ Content string
SearchType string
Captcha *types.CaptchaResponse
Dark bool
ShowNSFW bool
HideInstanceNames bool
+ HideThumbnails bool
}
func (s State) Unknown() string {
@@ -266,6 +271,18 @@ func (state *State) GetSite() {
return
}
state.Site = resp
+ if !state.Site.MyUser.IsValid() {
+ return
+ }
+ for _, c := range state.Site.MyUser.MustValue().Follows {
+ state.Session.Communities = append(state.Session.Communities, types.CommunityView{
+ Community: c.Community,
+ Subscribed: "Subscribed",
+ })
+ }
+ sort.Slice(state.Session.Communities, func(a, b int) bool {
+ return state.Session.Communities[a].Community.Name < state.Session.Communities[b].Community.Name
+ })
}
func (state *State) GetComment(commentid int) {
@@ -299,6 +316,9 @@ func (state *State) GetComment(commentid int) {
state.Comments = append(state.Comments, comment)
}
}
+ if len(state.Comments) == 0 {
+ return
+ }
ctx, err := state.GetContext(state.Context, state.Comments[0])
if err != nil {
fmt.Println(err)
@@ -531,16 +551,10 @@ func (state *State) Search(searchtype string) {
if state.Page > 1 {
return
}
- state.GetSite()
- for _, c := range state.Site.MyUser.MustValue().Follows {
- state.Communities = append(state.Communities, types.CommunityView{
- Community: c.Community,
- Subscribed: "Subscribed",
- })
+ if state.Site == nil {
+ state.GetSite()
}
- sort.Slice(state.Communities, func(a, b int) bool {
- return state.Communities[a].Community.Name < state.Communities[b].Community.Name
- })
+ state.Communities = state.Session.Communities
return
}
resp, err := state.Client.Communities(context.Background(), types.ListCommunities{
diff --git a/templates/comment.html b/templates/comment.html
index fb686b8..c33d77a 100644
--- a/templates/comment.html
+++ b/templates/comment.html
@@ -1,4 +1,4 @@
-
Preview
+