Only render notifications if they have changed.
[Sone.git] / src / main / resources / static / javascript / sone.js
index 21f6803..5aaa6a5 100644 (file)
@@ -33,7 +33,7 @@ function registerInputTextareaSwap(inputElement, defaultText, inputFieldName, op
                                inputField.val(defaultText);
                        }
                }).hide().data("inputField", $(this)).val($(this).val());
-               $(this).after(textarea);
+               $(this).data("textarea", textarea).after(textarea);
                (function(inputField, textarea) {
                        inputField.focus(function() {
                                $(this).hide().attr("disabled", "disabled");
@@ -66,11 +66,11 @@ function registerInputTextareaSwap(inputElement, defaultText, inputFieldName, op
  * @param element
  *            The element to add a “comment” link to
  */
-function addCommentLink(postId, element, insertAfterThisElement) {
+function addCommentLink(postId, author, element, insertAfterThisElement) {
        if (($(element).find(".show-reply-form").length > 0) || (getPostElement(element).find(".create-reply").length == 0)) {
                return;
        }
-       commentElement = (function(postId) {
+       commentElement = (function(postId, author) {
                separator = $("<span> · </span>").addClass("separator");
                var commentElement = $("<div><span>Comment</span></div>").addClass("show-reply-form").click(function() {
                        replyElement = $("#sone .post#" + postId + " .create-reply");
@@ -85,10 +85,11 @@ function addCommentLink(postId, element, insertAfterThisElement) {
                                        replyElement.removeClass("light");
                                });
                        })(replyElement);
-                       replyElement.find("input.reply-input").focus();
+                       textArea = replyElement.find("input.reply-input").focus().data("textarea");
+                       textArea.val(textArea.val() + "@sone://" + author + " ");
                });
                return commentElement;
-       })(postId);
+       })(postId, author);
        $(insertAfterThisElement).after(commentElement.clone(true));
        $(insertAfterThisElement).after(separator);
 }
@@ -218,7 +219,8 @@ function enhanceDeletePostButton(button, postId, text) {
                        if (data.success) {
                                $("#sone .post#" + postId).slideUp();
                        } else if (data.error == "invalid-post-id") {
-                               alert("Invalid post ID given!");
+                               /* pretend the post is already gone. */
+                               getPost(postId).slideUp();
                        } else if (data.error == "auth-required") {
                                alert("You need to be logged in.");
                        } else if (data.error == "not-authorized") {
@@ -249,7 +251,8 @@ function enhanceDeleteReplyButton(button, replyId, text) {
                        if (data.success) {
                                $("#sone .reply#" + replyId).slideUp();
                        } else if (data.error == "invalid-reply-id") {
-                               alert("Invalid reply ID given!");
+                               /* pretend the reply is already gone. */
+                               getReply(replyId).slideUp();
                        } else if (data.error == "auth-required") {
                                alert("You need to be logged in.");
                        } else if (data.error == "not-authorized") {
@@ -413,6 +416,17 @@ function getNotificationId(notificationElement) {
        return $(notificationElement).attr("id");
 }
 
+/**
+ * Returns the time the notification was last updated.
+ *
+ * @param notificationElement
+ *            The notification element
+ * @returns The last update time of the notification
+ */
+function getNotificationLastUpdatedTime(notificationElement) {
+       return $(notificationElement).attr("lastUpdatedTime");
+}
+
 function likePost(postId) {
        $.getJSON("like.ajax", { "type": "post", "post" : postId, "formPassword": getFormPassword() }, function(data, textStatus) {
                if ((data == null) || !data.success) {
@@ -664,7 +678,7 @@ function ajaxifySone(soneElement) {
 
        /* mark Sone as known when clicking it. */
        $(soneElement).click(function() {
-               markSoneAsKnown(soneElement);
+               markSoneAsKnown(this);
        });
 }
 
@@ -755,7 +769,7 @@ function ajaxifyPost(postElement) {
        });
 
        /* add “comment” link. */
-       addCommentLink(getPostId(postElement), postElement, $(postElement).find(".post-status-line .time"));
+       addCommentLink(getPostId(postElement), getPostAuthor(postElement), postElement, $(postElement).find(".post-status-line .time"));
 
        /* process all replies. */
        replyIds = [];
@@ -815,7 +829,7 @@ function ajaxifyReply(replyElement) {
                        });
                });
        })(replyElement);
-       addCommentLink(getPostId(replyElement), replyElement, $(replyElement).find(".reply-status-line .time"));
+       addCommentLink(getPostId(replyElement), getReplyAuthor(replyElement), replyElement, $(replyElement).find(".reply-status-line .time"));
 
        /* convert “show source” link into javascript function. */
        $(replyElement).find(".show-reply-source").each(function() {
@@ -999,29 +1013,24 @@ function getStatus() {
                                        }
                                        $(this).slideUp("normal", function() {
                                                $(this).remove();
+                                               /* remove activity when no notifications are visible. */
+                                               if ($("#sone #notification-area .notification").length == 0) {
+                                                       resetActivity();
+                                               }
                                        });
                                }
                        });
                        /* process notifications. */
+                       notificationIds = [];
                        $.each(data.notifications, function(index, value) {
                                oldNotification = getNotification(value.id);
-                               notification = ajaxifyNotification(createNotification(value.id, value.text, value.dismissable)).hide();
-                               if (oldNotification.length != 0) {
-                                       if ((oldNotification.find(".short-text").length > 0) && (notification.find(".short-text").length > 0)) {
-                                               opened = oldNotification.is(":visible") && oldNotification.find(".short-text").hasClass("hidden");
-                                               notification.find(".short-text").toggleClass("hidden", opened);
-                                               notification.find(".text").toggleClass("hidden", !opened);
-                                       }
-                                       checkForRemovedSones(oldNotification, notification);
-                                       checkForRemovedPosts(oldNotification, notification);
-                                       checkForRemovedReplies(oldNotification, notification);
-                                       oldNotification.replaceWith(notification.show());
-                               } else {
-                                       $("#sone #notification-area").append(notification);
-                                       notification.slideDown();
-                                       setActivity();
+                               if ((oldNotification.length == 0) || (value.lastUpdatedTime > getNotificationLastUpdatedTime(oldNotification))) {
+                                       notificationIds.push(value.id);
                                }
                        });
+                       if (notificationIds.length > 0) {
+                               loadNotifications(notificationIds);
+                       }
                        /* process new posts. */
                        $.each(data.newPosts, function(index, value) {
                                loadNewPost(value.id, value.sone, value.recipient, value.time);
@@ -1043,6 +1052,40 @@ function getStatus() {
 }
 
 /**
+ * Requests multiple notifications from Sone and displays them.
+ *
+ * @param notificationIds
+ *            Array of IDs of the notifications to load
+ */
+function loadNotifications(notificationIds) {
+       $.getJSON("getNotification.ajax", {"notifications": notificationIds.join(",")}, function(data, textStatus) {
+               if (!data || !data.success) {
+                       // TODO - show error
+                       return;
+               }
+               $.each(data.notifications, function(index, value) {
+                       oldNotification = getNotification(value.id);
+                       notification = ajaxifyNotification(createNotification(value.id, value.lastUpdatedTime, value.text, value.dismissable)).hide();
+                       if (oldNotification.length != 0) {
+                               if ((oldNotification.find(".short-text").length > 0) && (notification.find(".short-text").length > 0)) {
+                                       opened = oldNotification.is(":visible") && oldNotification.find(".short-text").hasClass("hidden");
+                                       notification.find(".short-text").toggleClass("hidden", opened);
+                                       notification.find(".text").toggleClass("hidden", !opened);
+                               }
+                               checkForRemovedSones(oldNotification, notification);
+                               checkForRemovedPosts(oldNotification, notification);
+                               checkForRemovedReplies(oldNotification, notification);
+                               oldNotification.replaceWith(notification.show());
+                       } else {
+                               $("#sone #notification-area").append(notification);
+                               notification.slideDown();
+                               setActivity();
+                       }
+               })
+       });
+}
+
+/**
  * Returns the ID of the currently logged in Sone.
  *
  * @return The ID of the current Sone, or an empty string if no Sone is logged
@@ -1329,9 +1372,6 @@ function updatePostTimes(postIds) {
  *            The tooltip to show
  */
 function updateReplyTime(replyId, timeText, refreshTime, tooltip) {
-       if (!getReply(replyId).is(":visible")) {
-               return;
-       }
        getReply(replyId).find(".reply-status-line > .time").html(timeText).attr("title", tooltip);
        (function(replyId, refreshTime) {
                setTimeout(function() {
@@ -1361,6 +1401,7 @@ function resetActivity() {
        if (title.indexOf('(') == 0) {
                setTitle(title.substr(title.indexOf(' ') + 1));
        }
+       iconBlinking = false;
 }
 
 function setActivity() {
@@ -1399,7 +1440,7 @@ var iconBlinking = false;
  * showing the activity state, it is returned to normal.
  */
 function toggleIcon() {
-       if (focus) {
+       if (focus || !iconBlinking) {
                if (iconActive) {
                        changeIcon("images/icon.png");
                        iconActive = false;
@@ -1435,8 +1476,8 @@ function changeIcon(iconUrl) {
  *            <code>true</code> if the notification can be dismissed by the
  *            user
  */
-function createNotification(id, text, dismissable) {
-       notification = $("<div></div>").addClass("notification").attr("id", id);
+function createNotification(id, lastUpdatedTime, text, dismissable) {
+       notification = $("<div></div>").addClass("notification").attr("id", id).attr("lastUpdatedTime", lastUpdatedTime);
        if (dismissable) {
                dismissForm = $("#sone #notification-area #notification-dismiss-template").clone().removeClass("hidden").removeAttr("id")
                dismissForm.find("input[name=notification]").val(id);
@@ -1558,9 +1599,6 @@ $(document).ready(function() {
                        sender = $(this).find(":input[name=sender]").val();
                        text = $(this).find(":input[name=text]:enabled").val();
                        $.getJSON("createPost.ajax", { "formPassword": getFormPassword(), "sender": sender, "text": text }, function(data, textStatus) {
-                               if ((data != null) && data.success) {
-                                       loadNewPost(data.postId, data.sone, data.recipient);
-                               }
                                button.removeAttr("disabled");
                        });
                        $(this).find(":input[name=sender]").val(getCurrentSoneId());
@@ -1589,11 +1627,7 @@ $(document).ready(function() {
                $("#sone #post-message").submit(function() {
                        sender = $(this).find(":input[name=sender]").val();
                        text = $(this).find(":input[name=text]:enabled").val();
-                       $.getJSON("createPost.ajax", { "formPassword": getFormPassword(), "recipient": getShownSoneId(), "sender": sender, "text": text }, function(data, textStatus) {
-                               if ((data != null) && data.success) {
-                                       loadNewPost(data.postId, getCurrentSoneId());
-                               }
-                       });
+                       $.getJSON("createPost.ajax", { "formPassword": getFormPassword(), "recipient": getShownSoneId(), "sender": sender, "text": text });
                        $(this).find(":input[name=sender]").val(getCurrentSoneId());
                        $(this).find(":input[name=text]:enabled").val("").blur();
                        $(this).find(".sender").hide();