reply fixes #25, endless scrolling settings fixes #18, settings popup.

This commit is contained in:
Ryan Stafford 2023-07-08 16:51:42 -04:00
parent 08a7ec66d4
commit 34f349313f
8 changed files with 201 additions and 60 deletions

View file

@ -253,9 +253,12 @@ summary {
border-top: 1px dotted gray;
font-size: 12px;
}
.comment form.savecomment {
form.savecomment {
margin: 0px 0px 10px 10px;
}
.comment > .children > form.savecomment {
margin: 0px 0px 10px 20px;
}
.savecomment textarea {
width: 500px;
height: 100px;
@ -370,7 +373,6 @@ form.nsfw div {
}
.pager {
margin: 10px;
display: none;
}
.pager a {
padding: 1px 4px;
@ -381,10 +383,18 @@ form.nsfw div {
text-decoration: none;
color: #369;
}
.pager.hidden {
display: none;
}
#loadmore {
display: none;
}
#loadmore, #end {
visibility: hidden;
margin: 10px 0px;
}
#loadmore.show {
display: block;
}
#loadmore[disabled] {
visibility: visible;
}
@ -475,6 +485,23 @@ form.nsfw div {
position: relative;
color: #000;
}
#settings {
background-color: white;
border: 1px solid #888;
display: none;
position: absolute;
right: 10px;
top: 45px;
}
#settings form {
margin: 0px;
}
.dark #settings {
background-color: #262626;
}
#settings.open {
display: inline-block;
}
.expando.open{
display: block;
}
@ -980,7 +1007,7 @@ form.create input[type=file], form.create select {
}
.preferences label{
display: inline-block;
width: 120px;
width: 100px;
text-align: right;
}

View file

@ -1,8 +1,10 @@
function request(url, params, callback, errorcallback) {
function request(url, params, callback, errorcallback = function(){}) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
if (xmlHttp.readyState != 4 ) { return }
if (xmlHttp.status == 200) {
return callback(xmlHttp.responseText);
}
errorcallback(xmlHttp.responseText);
}
var method = "GET"
@ -41,7 +43,11 @@ function commentClick(e) {
var form = e.target.parentNode
if (form) {
data = new FormData(form)
if (("c"+data.get("commentid")) != targ.id) { return }
if (("c"+data.get("commentid")) == targ.id) {
} 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"
@ -114,6 +120,8 @@ function loadMore(e) {
toggle_images(true)
}
}
var loadmore = document.getElementById("loadmore")
if (loadmore) loadmore.className = "show"
}
else {
e.target.outerHTML = '<input id="end" type="submit" value="" disabled>'
@ -167,6 +175,47 @@ function formSubmit(e) {
return false
}
function open_settings(e) {
e.preventDefault()
var settings = document.getElementById("settings")
settings.className = "open"
request(e.target.href + "?xhr=1", "", function(res) {
settings.innerHTML = res
var options = document.getElementsByClassName("scripting")
for (var i = 0; i < options.length; i++) {
var input = options[i].getElementsByTagName('input')
if (!input.length) { continue }
if (localStorage.getItem(input[0].name) == "true") {
input[0].checked = "checked"
}
}
})
return false
}
function close_settings(e) {
e.preventDefault()
var settings = document.getElementById("settings")
settings.className = ""
return false
}
function save_settings(e) {
e = e || window.event;
var targ = e.currentTarget || e.srcElement || e;
var data = new FormData(targ)
console.log(data)
e.preventDefault()
var params = new URLSearchParams(data).toString()
request(targ.target, params, function(res) {
["endlessScrolling", "autoLoad"].map(function(x) {
localStorage.setItem(x, data.get(x)=="on")
})
window.location.reload()
})
return false;
}
function parse_youtube(url){
if (url.indexOf("youtu") == -1) return false
var regExp = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
@ -227,12 +276,22 @@ for (var i = 0; i < posts.length; i++) {
}
}
window.onscroll = function(ev) {
if ((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
if (localStorage.getItem("endlessScrolling") == "true") {
var pager = document.getElementsByClassName("pager")
if (pager.length) pager[0].className = "pager hidden"
var loadmore = document.getElementById("loadmore")
if (loadmore) loadmore.className = "show"
if (localStorage.getItem("autoLoad") == "true") {
window.onscroll = function(e) {
if ((window.innerHeight + Math.round(window.scrollY)) >= document.body.offsetHeight) {
var loadmore = document.getElementById("loadmore")
if (loadmore) {
loadmore.click()
}
}
};
}
}

View file

@ -147,7 +147,7 @@ var funcMap = template.FuncMap{
converted = re.ReplaceAllString(converted, `href="/`+host+`/$1`)
re = regexp.MustCompile(` !([a-zA-Z0-9]+)@([a-zA-Z0-9\.\-]+) `)
converted = re.ReplaceAllString(converted, ` <a href="/$2/c/$1">!$1@$2</a> `)
re = regexp.MustCompile(`::: spoiler (.*?)\n(.*?)\s:::`)
re = regexp.MustCompile(`::: spoiler (.*?)\n([\S\s]*?):::`)
converted = re.ReplaceAllString(converted, "<details><summary>$1</summary>$2</details>")
return template.HTML(converted)
},
@ -999,6 +999,7 @@ func UserOp(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
parentid, _ := strconv.Atoi(r.FormValue("parentid"))
state.GetComment(parentid)
}
if r.FormValue("submit") == "save" {
createComment := types.CreateComment{
Content: r.FormValue("content"),
PostID: state.PostID,
@ -1008,6 +1009,13 @@ func UserOp(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
}
resp, err := state.Client.CreateComment(context.Background(), createComment)
if err == nil {
if r.FormValue("xhr") != "" {
state.XHR = true
state.Comments = nil
state.GetComment(resp.CommentView.Comment.ID)
Render(w, "index.html", state)
return
}
postid := strconv.Itoa(state.PostID)
commentid := strconv.Itoa(resp.CommentView.Comment.ID)
r.URL.Path = "/" + state.Host + "/post/" + postid
@ -1015,8 +1023,16 @@ func UserOp(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
} else {
fmt.Println(err)
}
} else if r.FormValue("xhr") != "" {
w.Write([]byte{})
return
}
if r.FormValue("submit") == "cancel" {
r.URL.RawQuery = ""
}
case "edit_comment":
commentid, _ := strconv.Atoi(r.FormValue("commentid"))
if r.FormValue("submit") == "save" {
resp, err := state.Client.EditComment(context.Background(), types.EditComment{
CommentID: commentid,
Content: types.NewOptional(r.FormValue("content")),
@ -1028,6 +1044,16 @@ func UserOp(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
r.URL.Fragment = "c" + commentid
r.URL.RawQuery = ""
}
}
if r.FormValue("xhr") != "" {
state.XHR = true
state.GetComment(commentid)
Render(w, "index.html", state)
return
}
if r.FormValue("submit") == "cancel" {
r.URL.RawQuery = ""
}
case "delete_comment":
commentid, _ := strconv.Atoi(r.FormValue("commentid"))
resp, err := state.Client.DeleteComment(context.Background(), types.DeleteComment{

View file

@ -28,17 +28,25 @@
{{ end }}
</div>
{{ if eq .Op "edit" }}
<div class="content">
<form class="savecomment" method="POST">
<div>
<textarea required name="content">{{ .P.Comment.Content }}</textarea>
</div>
<input type="hidden" name="commentid" value="{{.P.Comment.ID}}">
<input type="hidden" name="op" value="edit_comment">
<input type="submit" value="save">
<input name="submit" type="submit" value="save">
<input name="submit" type="submit" value="cancel">
</form>
{{ else }}
<div class="content{{ if and .Selected}} highlight{{end}}">
{{if .P.Comment.Deleted}}[removed]{{else}}{{ markdown .State.Host .P.Comment.Content }}{{end}}
<div class="content">
{{if .P.Comment.Deleted}}
[removed]
{{else}}
<div {{ if and .Selected (not .State.XHR) (ne .State.Op "reply")}}class="highlight" {{end}}>
{{ markdown .State.Host .P.Comment.Content }}
</div>
{{end}}
{{ if eq .Op "source" }}
<div><textarea>{{.P.Comment.Content}}</textarea></div>
{{end}}
@ -73,14 +81,12 @@
{{ end }}
</form>
</li>
{{ if ne .Op "reply" }}
<li>
<a class="reply" for="c{{.P.Comment.ID}}" href="/{{.State.Host}}/comment/{{.P.Comment.ID}}?reply">
reply
</a>
</li>
{{ end }}
{{ end }}
{{ if gt .ChildCount 0 }}
<li><a class="hidechildren" for="c{{.P.Comment.ID}}" href=""><span class="hide">hide</span><span class="show">show {{ .ChildCount }}</span> child comments</a></li>
{{ end }}
@ -90,11 +96,12 @@
{{ if and (eq .State.Op "reply") (eq .State.CommentID .P.Comment.ID)}}
<form class="savecomment" method="POST">
<div>
<textarea required name="content"></textarea>
<textarea name="content"></textarea>
</div>
<input type="hidden" name="parentid" value="{{.P.Comment.ID}}">
<input type="hidden" name="op" value="create_comment">
<input type="submit" value="save">
<input type="submit" name="submit" value="save">
<input type="submit" name="submit" value="cancel">
</form>
{{ end}}
{{ range $ci, $child := .C }}{{ template "comment.html" $child }}{{end}}

View file

@ -2,7 +2,7 @@
<head>
<title>{{ if and .Community (ne .Community.CommunityView.Community.Title "")}}{{.Community.CommunityView.Community.Title}}{{else if ne .CommunityName ""}}/c/{{.CommunityName}}{{ else if .User}}overview for {{.User.PersonView.Person.Name}}{{else}}{{ host .Host }}{{end}}</title>
<link rel="shortcut icon" href="/{{.Host}}/icon.jpg">
<link rel="stylesheet" href="/_/static/style.css?v=14">
<link rel="stylesheet" href="/_/static/style.css?v=15">
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body {{ if .Dark }}class="dark"{{end}}>
@ -56,6 +56,6 @@
{{ template "sidebar.html" . }}
</main>
{{ end }}
<script src="/_/static/utils.js?v=7"></script>
<script src="/_/static/utils.js?v=9"></script>
</body>
</html>

View file

@ -3,21 +3,18 @@
<title>{{if and .Posts .PostID }}{{ (index .Posts 0).Post.Name}} : {{.CommunityName}}{{else if and .Community (ne .Community.CommunityView.Community.Title "")}}{{.Community.CommunityView.Community.Title}}{{else if ne .CommunityName ""}}/c/{{.CommunityName}}{{ else if .User}}overview for {{.User.PersonView.Person.Name}}{{else}}{{ host .Host }}{{end}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="/{{.Host}}/icon.jpg">
<link rel="stylesheet" href="/_/static/style.css?v=14">
<link rel="stylesheet" href="/_/static/style.css?v=15">
</head>
<body{{ if .Dark }} class="dark"{{end}}>
<noscript>
<style>
.scripting,
.expando-button,
.minimize,
#loadmore,
#showimages,
.hidechildren {
display: none !important;
}
div.pager {
display: block;
}
.post .expando .image img {
visibility: visible;
}
@ -99,7 +96,7 @@
<textarea required name="content" {{ if (index .Posts 0).Post.Deleted }} disabled {{end}}></textarea>
</div>
<input type="hidden" name="op" value="create_comment">
<input type="submit" value="save"{{ if (index .Posts 0).Post.Deleted }} disabled {{end}}>
<input type="submit" name="submit" value="save"{{ if (index .Posts 0).Post.Deleted }} disabled {{end}}>
</form>
{{ end }}
{{ end }}
@ -128,7 +125,7 @@
<input id="loadmore" type="submit" value="load more" onclick="loadMore(event)" data-page="2">
{{ end }}
<script src="/_/static/utils.js?v=7"></script>
<script src="/_/static/utils.js?v=9"></script>
{{ template "sidebar.html" . }}
</main>
{{ end }}

View file

@ -17,15 +17,16 @@
|
<a href="/{{.Host}}/inbox" class="mailbox{{ if .UnreadCount }} orangered{{end}}"></a>
|
<a href="/{{.Host}}/settings">settings</a>
<a href="/{{.Host}}/settings" onclick="open_settings(event)">settings</a>
|
<form method="POST"><input type="submit" name="op" value="logout"></form>
{{else}}
<a href="/{{.Host}}/login">log in</a> or <a href="/{{.Host}}/login">sign up</a>
|
<a href="/{{.Host}}/settings">settings</a>
<a href="/{{.Host}}/settings" onclick="open_settings(event)">settings</a>
{{end}}
</div>
<div id="settings"></div>
<div class="spacer">
<a href="/{{ .Host}}/">
<img class="icon" src="{{ if .Site }}{{ .Site.SiteView.Site.Icon.String }}{{else}}/{{ .Host}}/icon.jpg{{end}}">

View file

@ -1,11 +1,19 @@
{{ if not .XHR }}
<!DOCTYPE html>
<head>
<title>{{ host .Host }}: preferences</title>
<link rel="shortcut icon" href="/{{.Host}}/icon.jpg">
<link rel="stylesheet" href="/_/static/style.css?v=7">
<link rel="stylesheet" href="/_/static/style.css?v=15">
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body {{ if .Dark}}class="dark"{{end}}>
<noscript>
<style>
.scripting {
display: none;
}
</style>
</noscript>
<nav>
<div class="communities">
<a href="/{{.Host}}">home</a>
@ -52,7 +60,8 @@
{{ if .Error }}
<div class="error">{{.Error}}</div>
{{ end }}
<form class="preferences" method="POST">
{{ end }}
<form class="preferences" method="POST" target="/{{.Host}}/settings" onsubmit="save_settings(event)" >
<div>
<label>
default listing
@ -90,11 +99,26 @@
</label>
<input type="checkbox" name="darkmode" {{ if .Dark }}checked{{end}}>
</div>
<div class="scripting">
<label>
endless scrolling
</label>
<input type="checkbox" name="endlessScrolling">
</div>
<div class="scripting">
<label>
auto load more
</label>
<input type="checkbox" name="autoLoad">
</div>
<div>
<label></label>
<input type="submit" value="save">
{{ if .XHR }}<input type="submit" value="close" onclick="close_settings(event)">{{ end }}
</div>
</form>
{{ if not .XHR}}
<script src="/_/static/utils.js?v=8"></script>
</body>
</html>
{{ end }}