SSR: Repost ohne JS, return_to in Formularen, Werbebanner entfernt
Letzter vollständiger SSR-Stand vor dem Rückbau auf reine SPA. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TiXsPUqw7oeomZ8wZrQW5q
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c66df283d1
commit
eccddcebe6
+44
-4
@@ -80,6 +80,31 @@ type entryView struct {
|
||||
DeleteURL string
|
||||
}
|
||||
|
||||
// bumpRemaining ist die Restsperre des Reposts in Sekunden (0 = wieder
|
||||
// möglich). Spiegelt die Bedingung im UPDATE von handleBump; die Vorlage
|
||||
// braucht den Wert, um den Repost-Knopf zu sperren und die Wartezeit
|
||||
// anzuzeigen -- das Gegenstück zu setupBump in web/js/feed.js.
|
||||
func (v entryView) bumpRemaining() int64 {
|
||||
rem := v.LastBump + v.BumpCount*bumpStep - time.Now().Unix()
|
||||
if rem < 0 {
|
||||
return 0
|
||||
}
|
||||
return rem
|
||||
}
|
||||
|
||||
// BumpLocked meldet, ob der Repost dieses Beitrags gerade im Cooldown steckt.
|
||||
func (v entryView) BumpLocked() bool { return v.bumpRemaining() > 0 }
|
||||
|
||||
// BumpWaitHours ist die Restsperre auf volle Stunden aufgerundet (mindestens
|
||||
// 1, solange überhaupt Zeit übrig ist) -- wie die Anzeige im JS-Frontend.
|
||||
func (v entryView) BumpWaitHours() int64 {
|
||||
h := (v.bumpRemaining() + 3599) / 3600
|
||||
if h < 1 {
|
||||
return 1
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// composeForm hält die Eingaben des Beitragsformulars über einen
|
||||
// fehlgeschlagenen Versuch hinweg. Die angehängte Datei fehlt dabei
|
||||
// zwangsläufig: ein <input type="file"> lässt sich aus Sicherheitsgründen
|
||||
@@ -97,6 +122,13 @@ type feedView struct {
|
||||
PrevURL string
|
||||
NextURL string
|
||||
|
||||
// ReturnTo ist der Rücksprungort dieser Seite (beim GET die Seite selbst).
|
||||
// Das Beitragsformular trägt ihn als verstecktes Feld, damit er einen
|
||||
// abgelehnten Post übersteht -- sonst fiele das neu gerenderte Formular
|
||||
// samt seiner Interaktions-Knöpfe auf den Default "/" zurück (die noch per
|
||||
// JS bediente Startseite) statt auf "/feed".
|
||||
ReturnTo string
|
||||
|
||||
// CanPost steuert, ob das Beitragsformular erscheint. Ohne Anmeldung gibt
|
||||
// es nichts zu schreiben; über TOR wird das Schreiben abgelehnt (blockTOR),
|
||||
// und ein Formular, das beim Absenden immer scheitert, wäre schlechter als
|
||||
@@ -178,11 +210,13 @@ func buildFeedView(r *http.Request, uid int64, rootsOnly bool) (feedView, error)
|
||||
return feedView{}, Internal(err)
|
||||
}
|
||||
|
||||
back := returnTo(r)
|
||||
v := feedView{
|
||||
Entries: toEntryViews(entries, tallies, returnTo(r), viewer),
|
||||
Page: page,
|
||||
Pages: pages,
|
||||
IsTOR: isTOR(r),
|
||||
Entries: toEntryViews(entries, tallies, back, viewer),
|
||||
Page: page,
|
||||
Pages: pages,
|
||||
IsTOR: isTOR(r),
|
||||
ReturnTo: back,
|
||||
}
|
||||
v.CanPost = viewer != 0 && !v.IsTOR
|
||||
if page > 0 {
|
||||
@@ -203,6 +237,11 @@ type threadView struct {
|
||||
CanPost bool
|
||||
IsTOR bool
|
||||
Compose composeForm
|
||||
|
||||
// ReturnTo wie bei feedView: das Antwortformular trägt ihn versteckt mit,
|
||||
// damit eine abgelehnte Antwort die Interaktions-Knöpfe nicht auf "/"
|
||||
// zurückwirft statt auf den Thread.
|
||||
ReturnTo string
|
||||
}
|
||||
|
||||
// toEntryViews reichert Beiträge mit Abstimmungsstand, Rücksprungziel und
|
||||
@@ -272,6 +311,7 @@ func buildThreadView(r *http.Request, pid int64) (threadView, error) {
|
||||
Entry: toEntryViews([]Entry{t.Entry}, tallies, back, viewer)[0],
|
||||
Replies: toEntryViews(t.Replies, tallies, back, viewer),
|
||||
IsTOR: isTOR(r),
|
||||
ReturnTo: back,
|
||||
}
|
||||
// Auf einen gelöschten Beitrag lässt sich nicht antworten -- er hat keinen
|
||||
// Autor mehr und der Platzhalter soll den Thread nur zusammenhalten.
|
||||
|
||||
Reference in New Issue
Block a user