Add context menu to reply avatars.
[Sone.git] / src / main / resources / static / javascript / sone.js
index 9c082f1..3fcf907 100644 (file)
@@ -8,6 +8,9 @@ function ajaxGet(url, data, successCallback, errorCallback) {
                                successCallback(data, textStatus);
                        }
                }, "error": function(xmlHttpRequest, textStatus, errorThrown) {
+                       if (xmlHttpRequest.status == 403) {
+                               notLoggedIn = true;
+                       }
                        if (typeof errorCallback != "undefined") {
                                errorCallback();
                        } else {
@@ -80,7 +83,9 @@ function addCommentLink(postId, author, element, insertAfterThisElement) {
                                });
                        })(replyElement);
                        textArea = replyElement.find("input.reply-input").focus().data("textarea");
-                       textArea.val(textArea.val() + "@sone://" + author + " ");
+                       if (author != getCurrentSoneId()) {
+                               textArea.val(textArea.val() + "@sone://" + author + " ");
+                       }
                });
                return commentElement;
        })(postId, author);
@@ -278,6 +283,18 @@ function getSoneElement(element) {
 }
 
 /**
+ * Returns the ID of the sone of the context menu that contains the given
+ * element.
+ *
+ * @param element
+ *            The element within a context menu to get the Sone ID for
+ * @return The Sone ID
+ */
+function getMenuSone(element) {
+       return $(element).closest(".sone-menu").find(".sone-id").text();
+}
+
+/**
  * Generates a list of Sones by concatening the names of the given sones with a
  * new line character (ā€œ\nā€).
  *
@@ -797,6 +814,45 @@ function ajaxifyPost(postElement) {
 
        /* hide reply input field. */
        $(postElement).find(".create-reply").addClass("hidden");
+
+       /* show Sone menu when hovering over the avatar. */
+       $(postElement).find(".post-avatar").mouseover(function() {
+               $(".sone-post-menu", postElement).mouseleave(function() {
+                       $(this).fadeOut();
+               }).fadeIn();
+               return false;
+       });
+       (function(postElement) {
+               var soneId = $(".sone-id", postElement).text();
+               $(".sone-post-menu .follow", postElement).click(function() {
+                       var followElement = this;
+                       ajaxGet("followSone.ajax", { "sone": soneId, "formPassword": getFormPassword() }, function() {
+                               $(followElement).addClass("hidden");
+                               $(followElement).parent().find(".unfollow").removeClass("hidden");
+                               $("#sone .sone-menu").each(function() {
+                                       if (getMenuSone(this) == soneId) {
+                                               $(".follow", this).toggleClass("hidden", true);
+                                               $(".unfollow", this).toggleClass("hidden", false);
+                                       }
+                               });
+                       });
+                       return false;
+               });
+               $(".sone-post-menu .unfollow", postElement).click(function() {
+                       var unfollowElement = this;
+                       ajaxGet("unfollowSone.ajax", { "sone": soneId, "formPassword": getFormPassword() }, function() {
+                               $(unfollowElement).addClass("hidden");
+                               $(unfollowElement).parent().find(".follow").removeClass("hidden");
+                               $("#sone .sone-menu").each(function() {
+                                       if (getMenuSone(this) == soneId) {
+                                               $(".follow", this).toggleClass("hidden", false);
+                                               $(".unfollow", this).toggleClass("hidden", true);
+                                       }
+                               });
+                       });
+                       return false;
+               });
+       })(postElement);
 }
 
 /**
@@ -845,6 +901,45 @@ function ajaxifyReply(replyElement) {
                untrustSone(getReplyAuthor(this));
                return false;
        });
+
+       /* show Sone menu when hovering over the avatar. */
+       $(replyElement).find(".reply-avatar").mouseover(function() {
+               $(".sone-reply-menu", replyElement).mouseleave(function() {
+                       $(this).fadeOut();
+               }).fadeIn();
+               return false;
+       });
+       (function(replyElement) {
+               var soneId = $(".sone-id", replyElement).text();
+               $(".sone-menu .follow", replyElement).click(function() {
+                       var followElement = this;
+                       ajaxGet("followSone.ajax", { "sone": soneId, "formPassword": getFormPassword() }, function() {
+                               $(followElement).addClass("hidden");
+                               $(followElement).parent().find(".unfollow").removeClass("hidden");
+                               $("#sone .sone-menu").each(function() {
+                                       if (getMenuSone(this) == soneId) {
+                                               $(".follow", this).toggleClass("hidden", true);
+                                               $(".unfollow", this).toggleClass("hidden", false);
+                                       }
+                               });
+                       });
+                       return false;
+               });
+               $(".sone-menu .unfollow", replyElement).click(function() {
+                       var unfollowElement = this;
+                       ajaxGet("unfollowSone.ajax", { "sone": soneId, "formPassword": getFormPassword() }, function() {
+                               $(unfollowElement).addClass("hidden");
+                               $(unfollowElement).parent().find(".follow").removeClass("hidden");
+                               $("#sone .sone-menu").each(function() {
+                                       if (getMenuSone(this) == soneId) {
+                                               $(".follow", this).toggleClass("hidden", false);
+                                               $(".unfollow", this).toggleClass("hidden", true);
+                                       }
+                               });
+                       });
+                       return false;
+               });
+       })(replyElement);
 }
 
 /**
@@ -863,7 +958,11 @@ function ajaxifyNotification(notification) {
                notification.find(".text").addClass("hidden");
        }
        notification.find("form.mark-as-read button").click(function() {
-               ajaxGet("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": $(":input[name=type]", this.form).val(), "id": $(":input[name=id]", this.form).val()});
+               allIds = $(":input[name=id]", this.form).val().split(" ");
+               for (index = 0; index < allIds.length; index += 16) {
+                       ids = allIds.slice(index, index + 16).join(" ");
+                       ajaxGet("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": $(":input[name=type]", this.form).val(), "id": ids});
+               }
        });
        notification.find("a[class^='link-']").each(function() {
                linkElement = $(this);
@@ -976,6 +1075,10 @@ function getStatus() {
                        $.each(data.sones, function(index, value) {
                                updateSoneStatus(value.id, value.name, value.status, value.modified, value.locked, value.lastUpdatedUnknown ? null : value.lastUpdated, value.lastUpdatedText);
                        });
+                       notLoggedIn = !data.loggedIn;
+                       if (!notLoggedIn) {
+                               showOfflineMarker(!online);
+                       }
                        /* search for removed notifications. */
                        $("#sone #notification-area .notification").each(function() {
                                notificationId = $(this).attr("id");
@@ -1070,8 +1173,10 @@ function loadNotifications(notificationIds) {
                                oldNotification.replaceWith(notification.show());
                        } else {
                                $("#sone #notification-area").append(notification);
-                               notification.slideDown();
-                               setActivity();
+                               if (value.id.substring(0, 5) != "local") {
+                                       notification.slideDown();
+                                       setActivity();
+                               }
                        }
                });
        });
@@ -1202,7 +1307,7 @@ function loadNewPost(postId, soneId, recipientId, time) {
        }
        if (!isIndexPage() || (getPage(".pagination-index") > 1)) {
                if (!isViewPostPage() || (getShownPostId() != postId)) {
-                       if (!isViewSonePage() || ((getShownSoneId() != soneId) && (getShownSoneId() != recipientId))) {
+                       if (!isViewSonePage() || ((getShownSoneId() != soneId) && (getShownSoneId() != recipientId)) || (getPage(".post-navigation") > 1)) {
                                return;
                        }
                }
@@ -1215,7 +1320,7 @@ function loadNewPost(postId, soneId, recipientId, time) {
                        if (hasPost(data.post.id)) {
                                return;
                        }
-                       if ((!isIndexPage() || (getPage(".pagination-index") > 1)) && !(isViewSonePage() && ((getShownSoneId() == data.post.sone) || (getShownSoneId() == data.post.recipient)))) {
+                       if ((!isIndexPage() || (getPage(".pagination-index") > 1)) && !(isViewSonePage() && ((getShownSoneId() == data.post.sone) || (getShownSoneId() == data.post.recipient) || (getPage(".post-navigation") > 1)))) {
                                return;
                        }
                        var firstOlderPost = null;
@@ -1226,6 +1331,9 @@ function loadNewPost(postId, soneId, recipientId, time) {
                                }
                        });
                        newPost = $(data.post.html).addClass("hidden");
+                       if ($(".post-author-local", newPost).text() == "true") {
+                               newPost.removeClass("new");
+                       }
                        if (firstOlderPost != null) {
                                newPost.insertBefore(firstOlderPost);
                        }
@@ -1259,6 +1367,14 @@ function loadNewReply(replyId, soneId, postId, postSoneId) {
                                        }
                                });
                                newReply = $(data.reply.html).addClass("hidden");
+                               if ($(".reply-author-local", newReply).text() == "true") {
+                                       newReply.removeClass("new");
+                                       (function(newReply) {
+                                               setTimeout(function() {
+                                                       markReplyAsKnown(newReply, false);
+                                               }, 5000);
+                                       })(newReply);
+                               }
                                if (firstNewerReply != null) {
                                        newReply.insertBefore(firstNewerReply);
                                } else {
@@ -1299,15 +1415,15 @@ function markSoneAsKnown(soneElement, skipRequest) {
 function markPostAsKnown(postElements, skipRequest) {
        $(postElements).each(function() {
                postElement = this;
-               if ($(postElement).hasClass("new")) {
+               if ($(postElement).hasClass("new") || ((typeof skipRequest != "undefined") && !skipRequest)) {
                        (function(postElement) {
                                $(postElement).removeClass("new");
-                               $(".click-to-show", postElement).removeClass("new");
                                if ((typeof skipRequest == "undefined") || !skipRequest) {
                                        ajaxGet("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": "post", "id": getPostId(postElement)});
                                }
                        })(postElement);
                }
+               $(".click-to-show", postElement).removeClass("new");
        });
        markReplyAsKnown($(postElements).find(".reply"));
 }
@@ -1315,7 +1431,7 @@ function markPostAsKnown(postElements, skipRequest) {
 function markReplyAsKnown(replyElements, skipRequest) {
        $(replyElements).each(function() {
                replyElement = this;
-               if ($(replyElement).hasClass("new")) {
+               if ($(replyElement).hasClass("new") || ((typeof skipRequest != "undefined") && !skipRequest)) {
                        (function(replyElement) {
                                $(replyElement).removeClass("new");
                                if ((typeof skipRequest == "undefined") || !skipRequest) {
@@ -1586,7 +1702,7 @@ var statusRequestQueued = true;
  */
 function ajaxError() {
        online = false;
-       toggleOfflineMarker(true);
+       showOfflineMarker(true);
        if (!statusRequestQueued) {
                setTimeout(getStatus, 5000);
                statusRequestQueued = true;
@@ -1598,7 +1714,7 @@ function ajaxError() {
  */
 function ajaxSuccess() {
        online = true;
-       toggleOfflineMarker(false);
+       showOfflineMarker(!online || (initiallyLoggedIn && notLoggedIn));
 }
 
 /**
@@ -1608,7 +1724,7 @@ function ajaxSuccess() {
  *            {@code true} to display the offline marker, {@code false} to hide
  *            it
  */
-function toggleOfflineMarker(visible) {
+function showOfflineMarker(visible) {
        /* jQuery documentation says toggle() works the other way around?! */
        $("#sone #offline-marker").toggle(visible);
        if (visible) {
@@ -1624,6 +1740,8 @@ function toggleOfflineMarker(visible) {
 
 var focus = true;
 var online = true;
+var initiallyLoggedIn = $("#sone #loggedIn").text() == "true";
+var notLoggedIn = !initiallyLoggedIn;
 
 $(document).ready(function() {
 
@@ -1709,7 +1827,7 @@ $(document).ready(function() {
                                allReplies = $(this).find(".reply");
                                if (allReplies.length > 2) {
                                        newHidden = false;
-                                       for (replyIndex = 0; replyIndex < (allReplies.length - 2); ++replyIndex) {
+                                       for (replyIndex = 0; !newHidden && (replyIndex < (allReplies.length - 2)); ++replyIndex) {
                                                $(allReplies[replyIndex]).addClass("hidden");
                                                newHidden |= $(allReplies[replyIndex]).hasClass("new");
                                        }