diff options
-rw-r--r-- | renderer/model.go | 5 | ||||
-rw-r--r-- | renderer/renderer.go | 1 | ||||
-rw-r--r-- | service/service.go | 8 | ||||
-rw-r--r-- | service/transport.go | 15 | ||||
-rw-r--r-- | static/fluoride.js | 71 | ||||
-rw-r--r-- | templates/statuspopup.tmpl | 15 |
6 files changed, 112 insertions, 3 deletions
diff --git a/renderer/model.go b/renderer/model.go index 4d09338..385ac7c 100644 --- a/renderer/model.go +++ b/renderer/model.go @@ -76,6 +76,11 @@ type QuickReplyData struct { PostContext model.PostContext } +type StatusData struct { + *CommonData + Status *mastodon.Status +} + type NotificationData struct { *CommonData Notifications []*mastodon.Notification diff --git a/renderer/renderer.go b/renderer/renderer.go index 0d6776c..f50e185 100644 --- a/renderer/renderer.go +++ b/renderer/renderer.go @@ -21,6 +21,7 @@ const ( TimelinePage = "timeline.tmpl" ThreadPage = "thread.tmpl" QuickReplyPage = "quickreply.tmpl" + StatusPopup = "status.tmpl" NotificationPage = "notification.tmpl" UserPage = "user.tmpl" UserSearchPage = "usersearch.tmpl" diff --git a/service/service.go b/service/service.go index 8297764..c56114c 100644 --- a/service/service.go +++ b/service/service.go @@ -378,6 +378,14 @@ func (s *service) QuickReplyPage(c *client, id string) (err error) { return s.renderer.Render(c.rctx, c.w, renderer.QuickReplyPage, data) } +func (svc *service) StatusPopup(c *client, id string) (err error) { + status, err := c.GetStatus(c.ctx, id) + if err != nil { + return + } + return svc.renderer.Render(c.rctx, c.w, renderer.StatusPopup, status) +} + func (s *service) LikedByPage(c *client, id string) (err error) { likers, err := c.GetFavouritedBy(c.ctx, id, nil) if err != nil { diff --git a/service/transport.go b/service/transport.go index 615fe2a..02e6106 100644 --- a/service/transport.go +++ b/service/transport.go @@ -54,6 +54,15 @@ func writeJson(c *client, data interface{}) error { }) } +func serveJsonError(w http.ResponseWriter, err error) { + var d = make(map[string]interface{}) + d["error"] = err.Error() + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusInternalServerError) + json.NewEncoder(w).Encode(d) + return +} + func redirect(c *client, url string) { c.w.Header().Add("Location", url) c.w.WriteHeader(http.StatusFound) @@ -640,6 +649,11 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { return writeJson(c, count) }, CSRF, JSON) + fStatus := handle(func(c *client) error { + id, _ := mux.Vars(c.r)["id"] + return s.StatusPopup(c, id) + }, SESSION, JSON) + r.HandleFunc("/", rootPage).Methods(http.MethodGet) r.HandleFunc("/nav", navPage).Methods(http.MethodGet) r.HandleFunc("/signin", signinPage).Methods(http.MethodGet) @@ -690,6 +704,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { r.HandleFunc("/fluoride/unlike/{id}", fUnlike).Methods(http.MethodPost) r.HandleFunc("/fluoride/retweet/{id}", fRetweet).Methods(http.MethodPost) r.HandleFunc("/fluoride/unretweet/{id}", fUnretweet).Methods(http.MethodPost) + r.HandleFunc("/fluoride/status/{id}", fStatus).Methods(http.MethodGet) r.PathPrefix("/static").Handler(http.StripPrefix("/static", http.FileServer(http.Dir(staticDir)))) diff --git a/static/fluoride.js b/static/fluoride.js index 6f14f86..279483f 100644 --- a/static/fluoride.js +++ b/static/fluoride.js @@ -7,6 +7,8 @@ var reverseActions = { "unretweet": "retweet" }; +var statusCache = {}; + var csrfToken = ""; var antiDopamineMode = false; @@ -33,11 +35,12 @@ function http(method, url, body, type, success, error) { }; req.onerror = function() { if (typeof error === "function") { - error(this.responseText); + error(this); } }; req.open(method, url); - req.setRequestHeader("Content-Type", type); + if (type) + req.setRequestHeader("Content-Type", type); req.send(body); } @@ -132,7 +135,7 @@ function isInView(el) { return false; } -function handleReplyToLink(a) { +function replyToLinkLocal(a) { if (!a) return; var id = a.getAttribute("href"); @@ -168,6 +171,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) { a.onmouseenter = function(event) { var id = event.target.getAttribute("href"); diff --git a/templates/statuspopup.tmpl b/templates/statuspopup.tmpl new file mode 100644 index 0000000..8cf9ead --- /dev/null +++ b/templates/statuspopup.tmpl @@ -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}} |