Add relative and dynamic timestamps to the web interface.
[Sone.git] / src / main / resources / static / javascript / sone.js
index c0fbb6d..86475e5 100644 (file)
@@ -37,7 +37,8 @@ function registerInputTextareaSwap(inputElement, defaultText, inputFieldName, op
                (function(inputField, textarea) {
                        inputField.focus(function() {
                                $(this).hide().attr("disabled", "disabled");
-                               textarea.show().focus();
+                               /* no, show(), “display: block” is not what I need. */
+                               textarea.attr("style", "display: inline").focus();
                        });
                        if (inputField.val() == "") {
                                inputField.addClass("default");
@@ -332,6 +333,17 @@ function getPostAuthor(element) {
        return getPostElement(element).find(".post-author").text();
 }
 
+/**
+ * Returns the element of the reply with the given ID.
+ *
+ * @param replyId
+ *            The ID of the reply
+ * @returns The element of the reply
+ */
+function getReply(replyId) {
+       return $("#sone .reply#" + replyId);
+}
+
 function getReplyElement(element) {
        return $(element).closest(".reply");
 }
@@ -561,25 +573,6 @@ function postReply(sender, postId, text, callbackFunction) {
 }
 
 /**
- * Requests information about the reply with the given ID.
- *
- * @param replyId
- *            The ID of the reply
- * @param callbackFunction
- *            A callback function (parameters soneId, soneName, replyTime,
- *            replyDisplayTime, text, html)
- */
-function getReply(replyId, callbackFunction) {
-       $.getJSON("getReply.ajax", { "reply" : replyId }, function(data, textStatus) {
-               if ((data != null) && data.success) {
-                       callbackFunction(data.soneId, data.soneName, data.time, data.displayTime, data.text, data.html);
-               }
-       }, function(xmlHttpRequest, textStatus, error) {
-               /* ignore error. */
-       });
-}
-
-/**
  * Ajaxifies the given Sone by enhancing all eligible elements with AJAX.
  *
  * @param soneElement
@@ -719,9 +712,12 @@ function ajaxifyPost(postElement) {
        addCommentLink(getPostId(postElement), postElement, $(postElement).find(".post-status-line .time"));
 
        /* process all replies. */
+       replyIds = [];
        $(postElement).find(".reply").each(function() {
+               replyIds.push(getReplyId(this));
                ajaxifyReply(this);
        });
+       updateReplyTimes(replyIds.join(","));
 
        /* process reply input fields. */
        getTranslation("WebInterface.DefaultText.Reply", function(text) {
@@ -844,6 +840,22 @@ function getStatus() {
                        $.each(data.sones, function(index, value) {
                                updateSoneStatus(value.id, value.name, value.status, value.modified, value.locked, value.lastUpdatedUnknown ? null : value.lastUpdated);
                        });
+                       /* search for removed notifications. */
+                       $("#sone #notification-area .notification").each(function() {
+                               notificationId = $(this).attr("id");
+                               foundNotification = false;
+                               $.each(data.notifications, function(index, value) {
+                                       if (value.id == notificationId) {
+                                               foundNotification = true;
+                                               return false;
+                                       }
+                               });
+                               if (!foundNotification) {
+                                       $(this).slideUp("normal", function() {
+                                               $(this).remove();
+                                       });
+                               }
+                       });
                        /* process notifications. */
                        $.each(data.notifications, function(index, value) {
                                oldNotification = $("#sone #notification-area .notification#" + value.id);
@@ -858,11 +870,8 @@ function getStatus() {
                                } else {
                                        $("#sone #notification-area").append(notification);
                                        notification.slideDown();
+                                       setActivity();
                                }
-                               setActivity();
-                       });
-                       $.each(data.removedNotifications, function(index, value) {
-                               $("#sone #notification-area .notification#" + value.id).slideUp();
                        });
                        /* process new posts. */
                        $.each(data.newPosts, function(index, value) {
@@ -1021,6 +1030,7 @@ function loadNewPost(postId, soneId, recipientId, time) {
                                newPost.insertBefore(firstOlderPost);
                        }
                        ajaxifyPost(newPost);
+                       updatePostTimes(data.post.id);
                        newPost.slideDown();
                        setActivity();
                }
@@ -1059,6 +1069,7 @@ function loadNewReply(replyId, soneId, postId, postSoneId) {
                                        }
                                }
                                ajaxifyReply(newReply);
+                               updateReplyTimes(data.reply.id);
                                newReply.slideDown();
                                setActivity();
                                return false;
@@ -1107,6 +1118,86 @@ function markReplyAsKnown(replyElements) {
        });
 }
 
+/**
+ * Updates the time of the post with the given ID.
+ *
+ * @param postId
+ *            The ID of the post to update
+ * @param timeText
+ *            The text of the time to show
+ * @param refreshTime
+ *            The refresh time after which to request a new time (in seconds)
+ * @param tooltip
+ *            The tooltip to show
+ */
+function updatePostTime(postId, timeText, refreshTime, tooltip) {
+       if (!getPost(postId).is(":visible")) {
+               return;
+       }
+       getPost(postId).find(".post-status-line > .time a").html(timeText).attr("title", tooltip);
+       (function(postId, refreshTime) {
+               setTimeout(function() {
+                       updatePostTimes(postId);
+               }, refreshTime * 1000);
+       })(postId, refreshTime);
+}
+
+/**
+ * Requests new rendered times for the posts with the given IDs.
+ *
+ * @param postIds
+ *            Comma-separated post IDs
+ */
+function updatePostTimes(postIds) {
+       $.getJSON("getTimes.ajax", { "posts" : postIds }, function(data, textStatus) {
+               if ((data != null) && data.success) {
+                       $.each(data.postTimes, function(index, value) {
+                               updatePostTime(index, value.timeText, value.refreshTime, value.tooltip);
+                       });
+               }
+       });
+}
+
+/**
+ * Updates the time of the reply with the given ID.
+ *
+ * @param postId
+ *            The ID of the reply to update
+ * @param timeText
+ *            The text of the time to show
+ * @param refreshTime
+ *            The refresh time after which to request a new time (in seconds)
+ * @param tooltip
+ *            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() {
+                       updateReplyTimes(replyId);
+               }, refreshTime * 1000);
+       })(replyId, refreshTime);
+}
+
+/**
+ * Requests new rendered times for the posts with the given IDs.
+ *
+ * @param postIds
+ *            Comma-separated post IDs
+ */
+function updateReplyTimes(replyIds) {
+       $.getJSON("getTimes.ajax", { "replies" : replyIds }, function(data, textStatus) {
+               if ((data != null) && data.success) {
+                       $.each(data.replyTimes, function(index, value) {
+                               updateReplyTime(index, value.timeText, value.refreshTime, value.tooltip);
+                       });
+               }
+       });
+}
+
 function resetActivity() {
        title = document.title;
        if (title.indexOf('(') == 0) {
@@ -1365,6 +1456,13 @@ $(document).ready(function() {
                });
        });
 
+       /* update post times. */
+       postIds = [];
+       $("#sone .post").each(function() {
+               postIds.push(getPostId(this));
+       });
+       updatePostTimes(postIds.join(","));
+
        /* hides all replies but the latest two. */
        if (!isViewPostPage()) {
                getTranslation("WebInterface.ClickToShow.Replies", function(text) {