Add fluoridated reply to popup

This commit is contained in:
r 2020-11-09 12:10:29 +00:00
parent 3a3a8672ba
commit c3f39210d8
8 changed files with 128 additions and 8 deletions

View File

@ -63,6 +63,11 @@ type ThreadData struct {
ReplyMap map[string][]mastodon.ReplyInfo ReplyMap map[string][]mastodon.ReplyInfo
} }
type StatusData struct {
*CommonData
Status *mastodon.Status
}
type NotificationData struct { type NotificationData struct {
*CommonData *CommonData
Notifications []*mastodon.Notification Notifications []*mastodon.Notification

View File

@ -20,6 +20,7 @@ const (
RootPage = "root.tmpl" RootPage = "root.tmpl"
TimelinePage = "timeline.tmpl" TimelinePage = "timeline.tmpl"
ThreadPage = "thread.tmpl" ThreadPage = "thread.tmpl"
StatusPopup = "status.tmpl"
NotificationPage = "notification.tmpl" NotificationPage = "notification.tmpl"
UserPage = "user.tmpl" UserPage = "user.tmpl"
UserSearchPage = "usersearch.tmpl" UserSearchPage = "usersearch.tmpl"

View File

@ -107,6 +107,14 @@ func (s *as) ServeThreadPage(c *model.Client, id string, reply bool) (err error)
return s.Service.ServeThreadPage(c, id, reply) return s.Service.ServeThreadPage(c, id, reply)
} }
func (s *as) ServeStatusPopup(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeStatusPopup(c, id)
}
func (s *as) ServeLikedByPage(c *model.Client, id string) (err error) { func (s *as) ServeLikedByPage(c *model.Client, id string) (err error) {
err = s.authenticateClient(c) err = s.authenticateClient(c)
if err != nil { if err != nil {

View File

@ -67,6 +67,14 @@ func (s *ls) ServeThreadPage(c *model.Client, id string,
return s.Service.ServeThreadPage(c, id, reply) return s.Service.ServeThreadPage(c, id, reply)
} }
func (s *ls) ServeStatusPopup(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"ServeStatusPopup", id, time.Since(begin), err)
}(time.Now())
return s.Service.ServeStatusPopup(c, id)
}
func (s *ls) ServeLikedByPage(c *model.Client, id string) (err error) { func (s *ls) ServeLikedByPage(c *model.Client, id string) (err error) {
defer func(begin time.Time) { defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n", s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",

View File

@ -28,6 +28,7 @@ type Service interface {
ServeTimelinePage(c *model.Client, tType string, maxID string, ServeTimelinePage(c *model.Client, tType string, maxID string,
minID string) (err error) minID string) (err error)
ServeThreadPage(c *model.Client, id string, reply bool) (err error) ServeThreadPage(c *model.Client, id string, reply bool) (err error)
ServeStatusPopup(c *model.Client, id string) (err error)
ServeLikedByPage(c *model.Client, id string) (err error) ServeLikedByPage(c *model.Client, id string) (err error)
ServeRetweetedByPage(c *model.Client, id string) (err error) ServeRetweetedByPage(c *model.Client, id string) (err error)
ServeNotificationPage(c *model.Client, maxID string, minID string) (err error) ServeNotificationPage(c *model.Client, maxID string, minID string) (err error)
@ -365,6 +366,15 @@ func (svc *service) ServeThreadPage(c *model.Client, id string, reply bool) (err
return svc.renderer.Render(rCtx, c.Writer, renderer.ThreadPage, data) return svc.renderer.Render(rCtx, c.Writer, renderer.ThreadPage, data)
} }
func (svc *service) ServeStatusPopup(c *model.Client, id string) (err error) {
status, err := c.GetStatus(ctx, id)
if err != nil {
return
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.StatusPopup, status)
}
func (svc *service) ServeLikedByPage(c *model.Client, id string) (err error) { func (svc *service) ServeLikedByPage(c *model.Client, id string) (err error) {
likers, err := c.GetFavouritedBy(ctx, id, nil) likers, err := c.GetFavouritedBy(ctx, id, nil)
if err != nil { if err != nil {

View File

@ -62,6 +62,7 @@ func serveJson(w io.Writer, data interface{}) (err error) {
func serveJsonError(w http.ResponseWriter, err error) { func serveJsonError(w http.ResponseWriter, err error) {
var d = make(map[string]interface{}) var d = make(map[string]interface{})
d["error"] = err.Error() d["error"] = err.Error()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(d) json.NewEncoder(w).Encode(d)
return return
@ -796,6 +797,17 @@ func NewHandler(s Service, staticDir string) http.Handler {
} }
} }
statusPopup := func(w http.ResponseWriter, req *http.Request) {
c := newClient(w, req, "")
id, _ := mux.Vars(req)["id"]
err := s.ServeStatusPopup(c, id)
if err != nil {
serveJsonError(w, err)
return
}
}
r.HandleFunc("/", rootPage).Methods(http.MethodGet) r.HandleFunc("/", rootPage).Methods(http.MethodGet)
r.HandleFunc("/nav", navPage).Methods(http.MethodGet) r.HandleFunc("/nav", navPage).Methods(http.MethodGet)
r.HandleFunc("/signin", signinPage).Methods(http.MethodGet) r.HandleFunc("/signin", signinPage).Methods(http.MethodGet)
@ -840,6 +852,7 @@ func NewHandler(s Service, staticDir string) http.Handler {
r.HandleFunc("/fluoride/unlike/{id}", fUnlike).Methods(http.MethodPost) r.HandleFunc("/fluoride/unlike/{id}", fUnlike).Methods(http.MethodPost)
r.HandleFunc("/fluoride/retweet/{id}", fRetweet).Methods(http.MethodPost) r.HandleFunc("/fluoride/retweet/{id}", fRetweet).Methods(http.MethodPost)
r.HandleFunc("/fluoride/unretweet/{id}", fUnretweet).Methods(http.MethodPost) r.HandleFunc("/fluoride/unretweet/{id}", fUnretweet).Methods(http.MethodPost)
r.HandleFunc("/fluoride/status/{id}", statusPopup).Methods(http.MethodGet)
r.PathPrefix("/static").Handler(http.StripPrefix("/static", r.PathPrefix("/static").Handler(http.StripPrefix("/static",
http.FileServer(http.Dir(staticDir)))) http.FileServer(http.Dir(staticDir))))

View File

@ -7,6 +7,8 @@ var reverseActions = {
"unretweet": "retweet" "unretweet": "retweet"
}; };
var statusCache = {};
var csrfToken = ""; var csrfToken = "";
var antiDopamineMode = false; var antiDopamineMode = false;
@ -33,11 +35,12 @@ function http(method, url, body, type, success, error) {
}; };
req.onerror = function() { req.onerror = function() {
if (typeof error === "function") { if (typeof error === "function") {
error(this.responseText); error(this);
} }
}; };
req.open(method, url); req.open(method, url);
req.setRequestHeader("Content-Type", type); if (type)
req.setRequestHeader("Content-Type", type);
req.send(body); req.send(body);
} }
@ -132,12 +135,7 @@ function isInView(el) {
return false; return false;
} }
function handleReplyToLink(a) { function replyToLinkLocal(a) {
if (!a)
return;
var id = a.getAttribute("href");
if (!id || id[0] != "#")
return;
a.onmouseenter = function(event) { a.onmouseenter = function(event) {
var id = event.target.getAttribute("href"); var id = event.target.getAttribute("href");
var status = document.querySelector(id); var status = document.querySelector(id);
@ -168,6 +166,68 @@ function handleReplyToLink(a) {
} }
} }
var inMouseEnter = false;
function replyToLinkRemote(a) {
a.onmouseenter = function(event) {
inMouseEnter = true;
var id = event.target.getAttribute("href");
var arr = id.replace("/thread", "").split("#");
if (arr.length < 2)
return
id = arr[1].replace("status-", "");
if (statusCache[id]) {
var copy = document.createElement("div");
copy.innerHTML = statusCache[id];
copy = copy.firstElementChild;
copy.id = "reply-to-popup";
var ract = event.target.getBoundingClientRect();
if (ract.top > window.innerHeight / 2) {
copy.style.bottom = (window.innerHeight -
window.scrollY - ract.top) + "px";
}
event.target.parentElement.appendChild(copy);
} else {
http("GET", "/fluoride/status/"+id, null, null, function(res, type) {
statusCache[id] = res;
if (!inMouseEnter)
return;
var copy = document.createElement("div");
copy.innerHTML = res;
copy = copy.firstElementChild;
copy.id = "reply-to-popup";
var ract = event.target.getBoundingClientRect();
if (ract.top > window.innerHeight / 2) {
copy.style.bottom = (window.innerHeight -
window.scrollY - ract.top) + "px";
}
event.target.parentElement.appendChild(copy);
}, function(err) {
console.log("error:", err);
})
}
}
a.onmouseleave = function(event) {
inMouseEnter = false;
var popup = document.getElementById("reply-to-popup");
if (popup) {
popup.parentElement.removeChild(popup);
}
}
}
function handleReplyToLink(a) {
if (!a)
return;
var id = a.getAttribute("href");
if (!id)
return;
if (id[0] === "#") {
replyToLinkLocal(a);
} else if (id.indexOf("/thread/") === 0) {
replyToLinkRemote(a);
}
}
function handleReplyLink(a) { function handleReplyLink(a) {
a.onmouseenter = function(event) { a.onmouseenter = function(event) {
var id = event.target.getAttribute("href"); var id = event.target.getAttribute("href");

View File

@ -0,0 +1,15 @@
{{with $s := .Data}}
{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
<div class="page-title"> Thread </div>
{{range .Statuses}}
{{template "status.tmpl" (WithContext . $.Ctx)}}
{{if $s.PostContext.ReplyContext}}{{if eq .ID $s.PostContext.ReplyContext.InReplyToID}}
{{template "postform.tmpl" (WithContext $s.PostContext $.Ctx)}}
{{end}}{{end}}
{{end}}
{{template "footer.tmpl"}}
{{end}}