aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--renderer/model.go5
-rw-r--r--renderer/renderer.go1
-rw-r--r--service/service.go9
-rw-r--r--service/transport.go15
-rw-r--r--static/fluoride.js71
-rw-r--r--templates/statuspopup.tmpl15
6 files changed, 113 insertions, 3 deletions
diff --git a/renderer/model.go b/renderer/model.go
index 6c3ba90..93cbbc6 100644
--- a/renderer/model.go
+++ b/renderer/model.go
@@ -66,6 +66,11 @@ type ThreadData struct {
ReplyMap map[string][]mastodon.ReplyInfo
}
+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 3d4685f..724178e 100644
--- a/renderer/renderer.go
+++ b/renderer/renderer.go
@@ -20,6 +20,7 @@ const (
RootPage = "root.tmpl"
TimelinePage = "timeline.tmpl"
ThreadPage = "thread.tmpl"
+ StatusPopup = "status.tmpl"
NotificationPage = "notification.tmpl"
UserPage = "user.tmpl"
UserSearchPage = "usersearch.tmpl"
diff --git a/service/service.go b/service/service.go
index ce689fd..1666959 100644
--- a/service/service.go
+++ b/service/service.go
@@ -305,6 +305,15 @@ func (s *service) ThreadPage(c *client, id string, reply bool) (err error) {
return s.renderer.Render(rCtx, c, renderer.ThreadPage, data)
}
+func (svc *service) StatusPopup(c *client, id string) (err error) {
+ status, err := c.GetStatus(ctx, id)
+ if err != nil {
+ return
+ }
+ rCtx := getRendererContext(c)
+ return svc.renderer.Render(rCtx, c, renderer.StatusPopup, status)
+}
+
func (s *service) LikedByPage(c *client, id string) (err error) {
likers, err := c.GetFavouritedBy(ctx, id, nil)
if err != nil {
diff --git a/service/transport.go b/service/transport.go
index 096b44e..9841650 100644
--- a/service/transport.go
+++ b/service/transport.go
@@ -64,6 +64,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.Header().Add("Location", url)
c.WriteHeader(http.StatusFound)
@@ -632,6 +641,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.Req)["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)
@@ -678,6 +692,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 36a374f..8244d80 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}}