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");
* @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");
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);
}
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") {
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") {
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) {
/* mark Sone as known when clicking it. */
$(soneElement).click(function() {
- markSoneAsKnown(soneElement);
+ markSoneAsKnown(this);
});
}
});
/* 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 = [];
});
});
})(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() {
return notification;
}
+/**
+ * Retrieves element IDs from notification elements.
+ *
+ * @param notification
+ * The notification element
+ * @param selector
+ * The selector of the element containing the ID as text
+ * @returns All extracted IDs
+ */
+function getElementIds(notification, selector) {
+ elementIds = [];
+ $(selector, notification).each(function() {
+ elementIds.push($(this).text());
+ });
+ return elementIds;
+}
+
+/**
+ * Compares the given notification elements and calls {@link #markSoneAsKnown()}
+ * for every ID that is contained in the old notification but not in the new.
+ *
+ * @param oldNotification
+ * The old notification element
+ * @param newNotification
+ * The new notification element
+ */
+function checkForRemovedSones(oldNotification, newNotification) {
+ if (getNotificationId(oldNotification) != "new-sone-notification") {
+ return;
+ }
+ oldIds = getElementIds(oldNotification, ".sone-id");
+ newIds = getElementIds(newNotification, ".sone-id");
+ $.each(oldIds, function(index, value) {
+ if ($.inArray(value, newIds) == -1) {
+ markSoneAsKnown(getSone(value), true);
+ }
+ });
+}
+
+/**
+ * Compares the given notification elements and calls {@link #markPostAsKnown()}
+ * for every ID that is contained in the old notification but not in the new.
+ *
+ * @param oldNotification
+ * The old notification element
+ * @param newNotification
+ * The new notification element
+ */
+function checkForRemovedPosts(oldNotification, newNotification) {
+ if (getNotificationId(oldNotification) != "new-post-notification") {
+ return;
+ }
+ oldIds = getElementIds(oldNotification, ".post-id");
+ newIds = getElementIds(newNotification, ".post-id");
+ $.each(oldIds, function(index, value) {
+ if ($.inArray(value, newIds) == -1) {
+ markPostAsKnown(getPost(value), true);
+ }
+ });
+}
+
+/**
+ * Compares the given notification elements and calls
+ * {@link #markReplyAsKnown()} for every ID that is contained in the old
+ * notification but not in the new.
+ *
+ * @param oldNotification
+ * The old notification element
+ * @param newNotification
+ * The new notification element
+ */
+function checkForRemovedReplies(oldNotification, newNotification) {
+ if (getNotificationId(oldNotification) != "new-replies-notification") {
+ return;
+ }
+ oldIds = getElementIds(oldNotification, ".reply-id");
+ newIds = getElementIds(newNotification, ".reply-id");
+ $.each(oldIds, function(index, value) {
+ if ($.inArray(value, newIds) == -1) {
+ markReplyAsKnown(getReply(value), true);
+ }
+ });
+}
+
function getStatus() {
$.getJSON("getStatus.ajax", {"loadAllSones": isKnownSonesPage()}, function(data, textStatus) {
if ((data != null) && data.success) {
}
});
if (!foundNotification) {
+ if (notificationId == "new-sone-notification") {
+ $(".sone-id", this).each(function(index, element) {
+ soneId = $(this).text();
+ markSoneAsKnown(getSone(soneId), true);
+ });
+ } else if (notificationId == "new-post-notification") {
+ $(".post-id", this).each(function(index, element) {
+ postId = $(this).text();
+ markPostAsKnown(getPost(postId), true);
+ });
+ } else if (notificationId == "new-replies-notification") {
+ $(".reply-id", this).each(function(index, element) {
+ replyId = $(this).text();
+ markReplyAsKnown(getReply(replyId), true);
+ });
+ }
$(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);
- }
- 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);
}
/**
+ * 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
* 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() {
if (title.indexOf('(') == 0) {
setTitle(title.substr(title.indexOf(' ') + 1));
}
+ iconBlinking = false;
}
function setActivity() {
* showing the activity state, it is returned to normal.
*/
function toggleIcon() {
- if (focus) {
+ if (focus || !iconBlinking) {
if (iconActive) {
changeIcon("images/icon.png");
iconActive = false;
* <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);
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());
$("#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();