csp and http only cookies

This commit is contained in:
Ryan Stafford 2023-07-10 11:53:15 -04:00
parent bf0bc421cd
commit 7ca1e23acf
9 changed files with 109 additions and 68 deletions

View file

@ -167,10 +167,10 @@ summary {
.comment { .comment {
font-size: 14px; font-size: 14px;
margin: 0px 0px 5px 15px; margin: 0px 0px 5px 0px;
border: 1px solid #e6e6e6; border: 1px solid #e6e6e6;
border-radius: 3px; border-radius: 3px;
padding: 5px 10px 5px 7px; padding: 10px 10px 0px 7px;
} }
.dark .comment { .dark .comment {
border-color: #333; border-color: #333;
@ -182,7 +182,6 @@ summary {
max-height: 300px; max-height: 300px;
} }
.comment .comment { .comment .comment {
margin-left: 15px;
} }
.comment .comment, .comment .comment,
.comment .comment .comment .comment, .comment .comment .comment .comment,
@ -243,18 +242,21 @@ summary {
} }
.commentmenu { .commentmenu {
font-size: 16px; font-size: 16px;
margin: 0px 0px 10px 10px; margin: 0px 0px 10px 0px;
} }
.commentmenu div { .commentmenu div {
border-top: 1px dotted gray; border-top: 1px dotted gray;
font-size: 12px; font-size: 12px;
} }
form.savecomment { form.savecomment {
margin: 0px 0px 10px 10px; margin: 0px 0px 10px 0px;
} }
.comment > .children > form.savecomment { .comment > .children > form.savecomment {
margin: 0px 0px 10px 20px; margin: 0px 0px 10px 20px;
} }
.comment .children {
margin: 5px 0px 10px 15px;
}
.savecomment textarea { .savecomment textarea {
width: 500px; width: 500px;
height: 100px; height: 100px;
@ -275,11 +277,13 @@ form.savecomment {
font-style: italic; font-style: italic;
font-weight: 700; font-weight: 700;
} }
.comment.hidden .content, .comment.hidden .children { .comment.hidden .content, .comment.hidden .children, .comment.hidden .morecomments {
display: none; display: none;
} }
.children .morecomments {
}
.morecomments { .morecomments {
margin: 10px 0px; margin: 0px 0px 10px 0px;
font-size: 10px; font-size: 10px;
} }
.morecomments a { .morecomments a {
@ -406,7 +410,7 @@ form.nsfw div {
width: 100%; width: 100%;
} }
.comment .buttons { .comment .buttons {
margin: 3px 0px 10px 0px; margin: 3px 0px 0px 0px;
} }
.comment.hidden .buttons { .comment.hidden .buttons {
display: none; display: none;
@ -481,7 +485,7 @@ form.nsfw div {
position: relative; position: relative;
color: #000; color: #000;
} }
#settings { #settingspopup {
background-color: white; background-color: white;
border: 1px solid #888; border: 1px solid #888;
display: none; display: none;
@ -489,13 +493,13 @@ form.nsfw div {
right: 10px; right: 10px;
top: 45px; top: 45px;
} }
#settings form { #settingspopup form {
margin: 0px; margin: 0px;
} }
.dark #settings { .dark #settingspopup {
background-color: #262626; background-color: #262626;
} }
#settings.open { #settingspopup.open {
display: inline-block; display: inline-block;
} }
.expando.open{ .expando.open{
@ -585,6 +589,7 @@ form.nsfw div {
} }
main { main {
position: relative; position: relative;
margin: 0px 10px;
} }
@media (min-width: 900px) { @media (min-width: 900px) {
.side { .side {
@ -594,8 +599,8 @@ main {
right: 0; right: 0;
} }
main { main {
padding-right: 310px; padding-right: 316px;
margin-left: 10px; margin-right: 0px;
} }
} }
.side form { .side form {

View file

@ -29,8 +29,8 @@ function postClick(e) {
bdy.className = 'expando open'; bdy.className = 'expando open';
btn.className = "expando-button open" btn.className = "expando-button open"
var url = targ.getElementsByClassName("url")[0].href var url = targ.getElementsByClassName("url")[0].href
if (id = parse_youtube(url)) { if (id = parseYoutube(url)) {
targ.getElementsByClassName("embed")[0].innerHTML = youtube_iframe(id) targ.getElementsByClassName("embed")[0].innerHTML = youtubeIframe(id)
} }
} }
} }
@ -114,23 +114,26 @@ function loadMore(e) {
request(window.location.origin+window.location.pathname+"?"+urlParams.toString(), "", request(window.location.origin+window.location.pathname+"?"+urlParams.toString(), "",
function(res){ function(res){
if (res.trim()) { if (res.trim()) {
e.target.outerHTML = res + '<input id="loadmore" type="submit" data-page="'+(parseInt(page)+1)+'" value="load more" onclick="loadMore(event)">' e.target.outerHTML = res + '<input id="loadmore" type="submit" data-page="'+(parseInt(page)+1)+'" value="load more">'
if (showimages = document.getElementById("showimages")) { if (showimages = document.getElementById("showimages")) {
if (showimages.className == "selected") { if (showimages.className == "selected") {
toggle_images(true) toggleImages(true)
} }
} }
var loadmore = document.getElementById("loadmore") var loadmore = document.getElementById("loadmore")
if (loadmore) loadmore.className = "show" loadmore.className = "show"
insert_youtube() loadmore.addEventListener("click", loadMore)
setup()
} }
else { else {
e.target.outerHTML = '<input id="end" type="submit" value="" disabled>' e.target.outerHTML = '<input id="end" type="submit" value="" disabled>'
} }
}, },
function(res) { function(res) {
e.target.outerHTML = '<input id="loadmore" type="submit" data-page="'+parseInt(page)+'" value="loading failed" onclick="loadMore(event)">' e.target.outerHTML = '<input id="loadmore" type="submit" data-page="'+parseInt(page)+'" value="loading failed">'
document.getElementById("loadmore").className = "show" var loadmore = document.getElementById("loadmore")
loadmore.className = "show"
loadmore.addEventListener("click", loadMore)
} }
) )
return false; return false;
@ -177,9 +180,9 @@ function formSubmit(e) {
return false return false
} }
function open_settings(e) { function openSettings(e) {
e.preventDefault() e.preventDefault()
var settings = document.getElementById("settings") var settings = document.getElementById("settingspopup")
settings.className = "open" settings.className = "open"
request(e.target.href + "?xhr=1", "", function(res) { request(e.target.href + "?xhr=1", "", function(res) {
settings.innerHTML = res settings.innerHTML = res
@ -191,22 +194,23 @@ function open_settings(e) {
input[0].checked = "checked" input[0].checked = "checked"
} }
} }
document.getElementById("settings").addEventListener("submit", saveSettings)
document.getElementById("closesettings").addEventListener("click", closeSettings)
}) })
return false return false
} }
function close_settings(e) { function closeSettings(e) {
e.preventDefault() e.preventDefault()
var settings = document.getElementById("settings") var settings = document.getElementById("settingspopup")
settings.className = "" settings.className = ""
return false return false
} }
function save_settings(e) { function saveSettings(e) {
e = e || window.event; e = e || window.event;
var targ = e.currentTarget || e.srcElement || e; var targ = e.currentTarget || e.srcElement || e;
var data = new FormData(targ) var data = new FormData(targ)
console.log(data)
e.preventDefault() e.preventDefault()
var params = new URLSearchParams(data).toString() var params = new URLSearchParams(data).toString()
request(targ.target, params, function(res) { request(targ.target, params, function(res) {
@ -218,7 +222,7 @@ function save_settings(e) {
return false; return false;
} }
function parse_youtube(url){ function parseYoutube(url){
if (url.indexOf("youtu") == -1) return false if (url.indexOf("youtu") == -1) return false
var regExp = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/; var regExp = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
var match = url.match(regExp); var match = url.match(regExp);
@ -227,27 +231,26 @@ function parse_youtube(url){
} }
return false return false
} }
function youtube_iframe(id) { function youtubeIframe(id) {
return '<iframe width="560" height="315" src="https://www.youtube.com/embed/'+id+'" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>' return '<iframe width="560" height="315" src="https://www.youtube.com/embed/'+id+'" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>'
} }
function show_images(e) { function showImages(e) {
e = e || window.event; e = e || window.event;
e.preventDefault() e.preventDefault()
var targ = e.currentTarget || e.srcElement || e; var targ = e.currentTarget || e.srcElement || e;
console.log(targ)
var parent = targ.parentNode var parent = targ.parentNode
if (parent.className == "") { if (parent.className == "") {
parent.className = "selected" parent.className = "selected"
toggle_images(true) toggleImages(true)
} else { } else {
parent.className = "" parent.className = ""
toggle_images(false) toggleImages(false)
} }
return false return false
} }
function toggle_images(open) { function toggleImages(open) {
var posts = document.getElementsByClassName("post") var posts = document.getElementsByClassName("post")
for (var i = 0; i < posts.length; i++) { for (var i = 0; i < posts.length; i++) {
var btn = posts[i].getElementsByClassName("expando-button")[0] var btn = posts[i].getElementsByClassName("expando-button")[0]
@ -265,27 +268,48 @@ function toggle_images(open) {
} }
} }
function insert_youtube() { function setup() {
if (showimages = document.getElementById("se")) {
showimages.addEventListener("click", showImages)
}
if (settings = document.getElementById("opensettings")) {
settings.addEventListener("click", openSettings)
}
if (hidechildren = document.getElementById("hidechildren")){
hidechildren.addEventListener("click", hideAllChildComments)
}
var posts = document.getElementsByClassName("post") var posts = document.getElementsByClassName("post")
for (var i = 0; i < posts.length; i++) { for (var i = 0; i < posts.length; i++) {
posts[i].addEventListener("click", postClick)
var voteForm = posts[i].getElementsByClassName("link-btn")
if (voteForm.length) {
voteForm[0].addEventListener("submit", formSubmit)
}
var url = posts[i].getElementsByClassName("url")[0].href var url = posts[i].getElementsByClassName("url")[0].href
if (id = parse_youtube(url)) { if (id = parseYoutube(url)) {
var btn = posts[i].getElementsByClassName("expando-button")[0] var btn = posts[i].getElementsByClassName("expando-button")[0]
if (btn.className.indexOf("open") > -1) { if (btn.className.indexOf("open") > -1) {
posts[i].getElementsByClassName("embed")[0].innerHTML = youtube_iframe(id) posts[i].getElementsByClassName("embed")[0].innerHTML = youtubeIframe(id)
} else { } else {
btn.className = "expando-button" btn.className = "expando-button"
} }
} }
} }
var comments = document.getElementsByClassName("comment")
for (var i = 0; i < comments.length; i++) {
comments[i].addEventListener("click", commentClick)
}
} }
insert_youtube() setup()
if (localStorage.getItem("endlessScrolling") == "true") { if (localStorage.getItem("endlessScrolling") == "true") {
var pager = document.getElementsByClassName("pager") var pager = document.getElementsByClassName("pager")
if (pager.length) pager[0].className = "pager hidden" if (pager.length) pager[0].className = "pager hidden"
var loadmore = document.getElementById("loadmore") var loadmore = document.getElementById("loadmore")
if (loadmore) loadmore.className = "show" if (loadmore) {
loadmore.className = "show"
loadmore.addEventListener("click", loadMore)
}
if (localStorage.getItem("autoLoad") == "true") { if (localStorage.getItem("autoLoad") == "true") {
window.onscroll = function(e) { window.onscroll = function(e) {
@ -299,4 +323,11 @@ if (localStorage.getItem("endlessScrolling") == "true") {
} }
} }
// delete cookies without HTTPOnly
var cookies = document.cookie.split(";");
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i];
var eqPos = cookie.indexOf("=");
var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;SameSite=None;Secure";
}

View file

@ -194,7 +194,7 @@ func Initialize(Host string, r *http.Request) (State, error) {
token := getCookie(r, "jwt") token := getCookie(r, "jwt")
user := getCookie(r, "user") user := getCookie(r, "user")
parts := strings.Split(user, ":") parts := strings.Split(user, ":")
if len(parts) == 2 { if len(parts) == 2 && token != "" {
if id, err := strconv.Atoi(parts[1]); err == nil { if id, err := strconv.Atoi(parts[1]); err == nil {
state.Client.Token = token state.Client.Token = token
sess := Session{ sess := Session{
@ -248,6 +248,8 @@ func Render(w http.ResponseWriter, templateName string, state State) {
if state.Status != http.StatusOK { if state.Status != http.StatusOK {
w.WriteHeader(state.Status) w.WriteHeader(state.Status)
} }
header := w.Header()
header.Set("Content-Security-Policy", "script-src 'self'")
err = tmpl.Execute(w, state) err = tmpl.Execute(w, state)
if err != nil { if err != nil {
fmt.Println("execute fail", err) fmt.Println("execute fail", err)
@ -507,6 +509,9 @@ func setCookie(w http.ResponseWriter, host string, name string, value string) {
Name: name, Name: name,
Value: value, Value: value,
MaxAge: 86400 * 30, MaxAge: 86400 * 30,
HttpOnly: true,
SameSite: http.SameSiteNoneMode,
Secure: true,
Path: "/" + host, Path: "/" + host,
} }
http.SetCookie(w, &cookie) http.SetCookie(w, &cookie)

View file

@ -1,5 +1,4 @@
<div class="comment{{if or (lt .P.Counts.Score -5) .P.Comment.Deleted }} hidden{{end}}" id="c{{.P.Comment.ID}}" onclick="commentClick(event)"> <div class="comment{{if or (lt .P.Counts.Score -5) .P.Comment.Deleted }} hidden{{end}}" id="c{{.P.Comment.ID}}">
<div class="meta">
{{ if .State.Session }} {{ if .State.Session }}
<div class="score"> <div class="score">
<form class="link-btn{{ if eq .P.MyVote.String "1"}} like{{ else if eq .P.MyVote.String "-1"}} dislike{{end}}" method="POST"> <form class="link-btn{{ if eq .P.MyVote.String "1"}} like{{ else if eq .P.MyVote.String "-1"}} dislike{{end}}" method="POST">
@ -14,6 +13,7 @@
</form> </form>
</div> </div>
{{ end }} {{ end }}
<div class="meta">
<a class="minimize" href="" for="c{{.P.Comment.ID}}"> <a class="minimize" href="" for="c{{.P.Comment.ID}}">
{{if or (lt .P.Counts.Score -5) .P.Comment.Deleted }} {{if or (lt .P.Counts.Score -5) .P.Comment.Deleted }}
[+] [+]
@ -105,7 +105,6 @@
</form> </form>
{{ end}} {{ end}}
{{ range $ci, $child := .C }}{{ template "comment.html" $child }}{{end}} {{ range $ci, $child := .C }}{{ template "comment.html" $child }}{{end}}
</div>
{{ if ne .P.Counts.ChildCount .ChildCount}} {{ if ne .P.Counts.ChildCount .ChildCount}}
<div class="morecomments"> <div class="morecomments">
<a class="loadmore" for="c{{ .P.Comment.ID}}" href="/{{.State.Host}}/comment/{{.P.Comment.ID}}?">load more comments</a> <a class="loadmore" for="c{{ .P.Comment.ID}}" href="/{{.State.Host}}/comment/{{.P.Comment.ID}}?">load more comments</a>
@ -113,3 +112,4 @@
</div> </div>
{{end}} {{end}}
</div> </div>
</div>

View file

@ -2,7 +2,7 @@
<head> <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> <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="shortcut icon" href="/{{.Host}}/icon.jpg">
<link rel="stylesheet" href="/_/static/style.css?v=16"> <link rel="stylesheet" href="/_/static/style.css?v=17">
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
</head> </head>
<body {{ if .Dark }}class="dark"{{end}}> <body {{ if .Dark }}class="dark"{{end}}>
@ -50,12 +50,12 @@
<div class="pager"> <div class="pager">
view more: {{if gt .Page 1 }}<a href="{{ .PrevPage }}"> prev</a>{{ end }} <a href="{{ .NextPage }}">next </a> view more: {{if gt .Page 1 }}<a href="{{ .PrevPage }}"> prev</a>{{ end }} <a href="{{ .NextPage }}">next </a>
</div> </div>
<input id="loadmore" type="submit" value="load more" onclick="loadMore(event)" data-page="2"> <input id="loadmore" type="submit" value="load more" data-page="2">
{{ end }} {{ end }}
{{ template "sidebar.html" . }} {{ template "sidebar.html" . }}
</main> </main>
{{ end }} {{ end }}
<script src="/_/static/utils.js?v=9"></script> <script src="/_/static/utils.js?v=12"></script>
</body> </body>
</html> </html>

View file

@ -3,7 +3,7 @@
<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> <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" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="/{{.Host}}/icon.jpg"> <link rel="shortcut icon" href="/{{.Host}}/icon.jpg">
<link rel="stylesheet" href="/_/static/style.css?v=16"> <link rel="stylesheet" href="/_/static/style.css?v=17">
</head> </head>
<body{{ if .Dark }} class="dark"{{end}}> <body{{ if .Dark }} class="dark"{{end}}>
<noscript> <noscript>
@ -122,10 +122,10 @@
<div class="pager"> <div class="pager">
view more: {{if gt .Page 1 }}<a href="{{ .PrevPage }}"> prev</a>{{ end }} <a href="{{ .NextPage }}">next </a> view more: {{if gt .Page 1 }}<a href="{{ .PrevPage }}"> prev</a>{{ end }} <a href="{{ .NextPage }}">next </a>
</div> </div>
<input id="loadmore" type="submit" value="load more" onclick="loadMore(event)" data-page="2"> <input id="loadmore" type="submit" value="load more" data-page="2">
{{ end }} {{ end }}
<script src="/_/static/utils.js?v=9"></script> <script src="/_/static/utils.js?v=12"></script>
{{ template "sidebar.html" . }} {{ template "sidebar.html" . }}
</main> </main>
{{ end }} {{ end }}

View file

@ -17,16 +17,16 @@
| |
<a href="/{{.Host}}/inbox" class="mailbox{{ if .UnreadCount }} orangered{{end}}"></a> <a href="/{{.Host}}/inbox" class="mailbox{{ if .UnreadCount }} orangered{{end}}"></a>
| |
<a href="/{{.Host}}/settings" onclick="open_settings(event)">settings</a> <a id="opensettings" href="/{{.Host}}/settings">settings</a>
| |
<form method="POST"><input type="submit" name="op" value="logout"></form> <form method="POST"><input type="submit" name="op" value="logout"></form>
{{else}} {{else}}
<a href="/{{.Host}}/login">log in</a> or <a href="/{{.Host}}/login">sign up</a> <a href="/{{.Host}}/login">log in</a> or <a href="/{{.Host}}/login">sign up</a>
| |
<a href="/{{.Host}}/settings" onclick="open_settings(event)">settings</a> <a id="opensettings" href="/{{.Host}}/settings">settings</a>
{{end}} {{end}}
</div> </div>
<div id="settings"></div> <div id="settingspopup"></div>
<div class="spacer"> <div class="spacer">
<a href="/{{ .Host}}/"> <a href="/{{ .Host}}/">
<img class="icon" src="{{ if .Site }}{{ .Site.SiteView.Site.Icon.String }}{{else}}/{{ .Host}}/icon.jpg{{end}}"> <img class="icon" src="{{ if .Site }}{{ .Site.SiteView.Site.Icon.String }}{{else}}/{{ .Host}}/icon.jpg{{end}}">
@ -66,7 +66,7 @@
<li{{ if eq .Sort "NewComments" }} class="selected"{{end}}><a href="{{ .SortBy "NewComments" }}">new comments</a></li> <li{{ if eq .Sort "NewComments" }} class="selected"{{end}}><a href="{{ .SortBy "NewComments" }}">new comments</a></li>
<li{{ if contains .Sort "Top" }} class="selected"{{end}}><a href="{{ .SortBy "TopDay" }}">top</a></li> <li{{ if contains .Sort "Top" }} class="selected"{{end}}><a href="{{ .SortBy "TopDay" }}">top</a></li>
{{ if .Posts }} {{ if .Posts }}
<li id="showimages"><a href="" onclick="show_images(event)">show images</a></li> <li id="showimages"><a id="se" href="">show images</a></li>
{{ end }} {{ end }}
{{ end }} {{ end }}
</ul> </ul>

View file

@ -1,12 +1,12 @@
{{ if ne .State.Op "vote_post" }} {{ if ne .State.Op "vote_post" }}
<div class="post{{if .Post.Deleted}} deleted{{end}}{{ if or .Post.FeaturedCommunity .Post.FeaturedLocal }} distinguished{{end}}" onclick="postClick(event)"> <div class="post{{if .Post.Deleted}} deleted{{end}}{{ if or .Post.FeaturedCommunity .Post.FeaturedLocal }} distinguished{{end}}">
{{ if gt .Rank 0 }} {{ if gt .Rank 0 }}
<div class="rank"> {{ .Rank }} </div> <div class="rank"> {{ .Rank }} </div>
{{ end }} {{ end }}
<div class="score"> <div class="score">
{{ end }} {{ end }}
{{ if .State.Session }} {{ if .State.Session }}
<form class="link-btn {{ if lt .Rank 1 }}squish{{end}}{{ if eq .MyVote.String "1" }} like{{else if eq .MyVote.String "-1"}} dislike{{end}}" method="POST" onsubmit="formSubmit(event)"> <form class="link-btn {{ if lt .Rank 1 }}squish{{end}}{{ if eq .MyVote.String "1" }} like{{else if eq .MyVote.String "-1"}} dislike{{end}}" method="POST">
<input type="submit" name="vote" value="▲"> <input type="submit" name="vote" value="▲">
{{ if .MyVote.IsValid}} {{ if .MyVote.IsValid}}
<input type="hidden" name="undo" value="{{.MyVote.String}}"> <input type="hidden" name="undo" value="{{.MyVote.String}}">
@ -71,7 +71,7 @@
</form> </form>
{{end}} {{end}}
{{ if .State.PostID }} {{ if .State.PostID }}
<a class="hidechildren" onclick="hideAllChildComments(event)" href="">hide all child comments</a> <a id="hidechildren" class="scripting" href="">hide all child comments</a>
{{ end }} {{ end }}
</div> </div>
</div> </div>

View file

@ -61,7 +61,7 @@
<div class="error">{{.Error}}</div> <div class="error">{{.Error}}</div>
{{ end }} {{ end }}
{{ end }} {{ end }}
<form class="preferences" method="POST" target="/{{.Host}}/settings" onsubmit="save_settings(event)" > <form id="settings" class="preferences" method="POST" target="/{{.Host}}/settings">
<div> <div>
<label> <label>
default listing default listing
@ -114,7 +114,7 @@
<div> <div>
<label></label> <label></label>
<input type="submit" value="save"> <input type="submit" value="save">
{{ if .XHR }}<input type="submit" value="close" onclick="close_settings(event)">{{ end }} {{ if .XHR }}<input id="closesettings" type="submit" value="close">{{ end }}
</div> </div>
</form> </form>
{{ if not .XHR}} {{ if not .XHR}}