X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fresources%2Fstatic%2Fjavascript%2Fsone.js;h=b44f19e2822e6cf498f1ec1b53b1baf95b37d52b;hb=412752b9c15f164dbabb7e4096eeb381cd00a5f4;hp=8a6411825db453d557a9f49e16d41b3818470304;hpb=faa26c42ce692d20bd5c22c3e1797729d7dea9e1;p=Sone.git diff --git a/src/main/resources/static/javascript/sone.js b/src/main/resources/static/javascript/sone.js index 8a64118..908faf5 100644 --- a/src/main/resources/static/javascript/sone.js +++ b/src/main/resources/static/javascript/sone.js @@ -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"); @@ -47,7 +48,9 @@ function registerInputTextareaSwap(inputElement, defaultText, inputFieldName, op textarea.show(); } $(inputField.get(0).form).submit(function() { + inputField.attr("disabled", "disabled"); if (!optional && (textarea.val() == "")) { + inputField.removeAttr("disabled").focus(); return false; } }); @@ -63,11 +66,12 @@ function registerInputTextareaSwap(inputElement, defaultText, inputFieldName, op * @param element * The element to add a âcommentâ link to */ -function addCommentLink(postId, element) { - if ($(element).find(".show-reply-form").length > 0) { +function addCommentLink(postId, element, insertAfterThisElement) { + if (($(element).find(".show-reply-form").length > 0) || (getPostElement(element).find(".create-reply").length == 0)) { return; } commentElement = (function(postId) { + separator = $(" · ").addClass("separator"); var commentElement = $("
true
if the current page is the index page,
+ * false
otherwise
+ */
+function isIndexPage() {
+ return getPageId() == "index";
+}
+
+/**
+ * Returns whether the current page is a âview Soneâ page.
+ *
+ * @returns {Boolean} true
if the current page is a âview Soneâ
+ * page, false
otherwise
+ */
+function isViewSonePage() {
+ return getPageId() == "view-sone";
+}
+
+/**
+ * Returns the ID of the currently shown Sone. This will only return a sensible
+ * value if isViewSonePage() returns true
.
+ *
+ * @returns The ID of the currently shown Sone
+ */
+function getShownSoneId() {
+ return $("#sone .sone-id").text();
+}
+
+/**
+ * Returns whether the current page is a âview postâ page.
+ *
+ * @returns {Boolean} true
if the current page is a âview postâ
+ * page, false
otherwise
+ */
+function isViewPostPage() {
+ return getPageId() == "view-post";
+}
+
+/**
+ * Returns the ID of the currently shown post. This will only return a sensible
+ * value if isViewPostPage() returns true
.
+ *
+ * @returns The ID of the currently shown post
+ */
+function getShownPostId() {
+ return $("#sone .post-id").text();
+}
+
+/**
+ * Returns whether the current page is the âknown Sonesâ page.
+ *
+ * @returns {Boolean} true
if the current page is the âknown
+ * Sonesâ page, false
otherwise
+ */
+function isKnownSonesPage() {
+ return getPageId() == "known-sones";
+}
+
+/**
+ * Returns whether a post with the given ID exists on the current page.
+ *
+ * @param postId
+ * The post ID to check for
+ * @returns {Boolean} true
if a post with the given ID already
+ * exists on the page, false
otherwise
+ */
+function hasPost(postId) {
+ return $(".post#" + postId).length > 0;
+}
+
+/**
+ * Returns whether a reply with the given ID exists on the current page.
+ *
+ * @param replyId
+ * The reply ID to check for
+ * @returns {Boolean} true
if a reply with the given ID already
+ * exists on the page, false
otherwise
+ */
+function hasReply(replyId) {
+ return $("#sone .reply#" + replyId).length > 0;
+}
+
+function loadNewPost(postId, soneId, recipientId, time) {
+ if (hasPost(postId)) {
return;
}
- loadedPosts[postId] = true;
- $.getJSON("ajax/getPost.ajax", { "post" : postId }, function(data, textStatus) {
+ if (!isIndexPage()) {
+ if (!isViewPostPage() || (getShownPostId() != postId)) {
+ if (!isViewSonePage() || ((getShownSoneId() != soneId) && (getShownSoneId() != recipientId))) {
+ return;
+ }
+ }
+ }
+ if (getPostTime($("#sone .post").last()) > time) {
+ return;
+ }
+ $.getJSON("getPost.ajax", { "post" : postId }, function(data, textStatus) {
if ((data != null) && data.success) {
+ if (hasPost(data.post.id)) {
+ return;
+ }
+ if (!isIndexPage() && !(isViewSonePage() && ((getShownSoneId() == data.post.sone) || (getShownSoneId() == data.post.recipient)))) {
+ return;
+ }
var firstOlderPost = null;
- $("#sone #posts .post").each(function() {
+ $("#sone .post").each(function() {
if (getPostTime(this) < data.post.time) {
firstOlderPost = $(this);
return false;
@@ -607,42 +1041,245 @@ function loadNewPost(postId) {
newPost = $(data.post.html).addClass("hidden");
if (firstOlderPost != null) {
newPost.insertBefore(firstOlderPost);
- } else {
- $("#sone #posts .post:last").after(newPost);
}
ajaxifyPost(newPost);
+ updatePostTimes(data.post.id);
newPost.slideDown();
+ setActivity();
}
});
}
-function loadNewReply(replyId) {
- if (replyId in loadedReplies) {
+function loadNewReply(replyId, soneId, postId, postSoneId) {
+ if (hasReply(replyId)) {
return;
}
- loadedReplies[replyId] = true;
- $.getJSON("ajax/getReply.ajax", { "reply": replyId }, function(data, textStatus) {
+ if (!hasPost(postId)) {
+ return;
+ }
+ $.getJSON("getReply.ajax", { "reply": replyId }, function(data, textStatus) {
/* find post. */
- $("#sone #posts .post#" + data.reply.postId).each(function() {
- var firstNewerReply = null;
- $(this).find(".replies .reply").each(function() {
- if (getReplyTime(this) > data.reply.time) {
- firstNewerReply = $(this);
- return false;
+ if ((data != null) && data.success) {
+ if (hasReply(data.reply.id)) {
+ return;
+ }
+ $("#sone .post#" + data.reply.postId).each(function() {
+ var firstNewerReply = null;
+ $(this).find(".replies .reply").each(function() {
+ if (getReplyTime(this) > data.reply.time) {
+ firstNewerReply = $(this);
+ return false;
+ }
+ });
+ newReply = $(data.reply.html).addClass("hidden");
+ if (firstNewerReply != null) {
+ newReply.insertBefore(firstNewerReply);
+ } else {
+ if ($(this).find(".replies .create-reply")) {
+ $(this).find(".replies .create-reply").before(newReply);
+ } else {
+ $(this).find(".replies").append(newReply);
+ }
}
+ ajaxifyReply(newReply);
+ updateReplyTimes(data.reply.id);
+ newReply.slideDown();
+ setActivity();
+ return false;
});
- newReply = $(data.reply.html);
- if (firstNewerReply != null) {
- newReply.insertAfter(firstNewerReply);
- } else {
- $(this).find(".replies .reply:last").after(newReply);
- }
- ajaxifyReply(newReply);
+ }
+ });
+}
+
+/**
+ * Marks the given Sone as known if it is still new.
+ *
+ * @param soneElement
+ * The Sone to mark as known
+ */
+function markSoneAsKnown(soneElement) {
+ if ($(".new", soneElement).length > 0) {
+ $.getJSON("maskAsKnown.ajax", {"formPassword": getFormPassword(), "type": "sone", "id": getSoneId(soneElement)}, function(data, textStatus) {
+ $(soneElement).removeClass("new");
});
+ }
+}
+
+function markPostAsKnown(postElements) {
+ $(postElements).each(function() {
+ postElement = this;
+ if ($(postElement).hasClass("new")) {
+ (function(postElement) {
+ $(postElement).removeClass("new");
+ $(".click-to-show", postElement).removeClass("new");
+ $.getJSON("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": "post", "id": getPostId(postElement)});
+ })(postElement);
+ }
+ });
+ markReplyAsKnown($(postElements).find(".reply"));
+}
+
+function markReplyAsKnown(replyElements) {
+ $(replyElements).each(function() {
+ replyElement = this;
+ if ($(replyElement).hasClass("new")) {
+ (function(replyElement) {
+ $(replyElement).removeClass("new");
+ $.getJSON("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": "reply", "id": getReplyId(replyElement)});
+ })(replyElement);
+ }
});
}
/**
+ * 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) {
+ setTitle(title.substr(title.indexOf(' ') + 1));
+ }
+}
+
+function setActivity() {
+ if (!focus) {
+ title = document.title;
+ if (title.indexOf('(') != 0) {
+ setTitle("(!) " + title);
+ }
+ if (!iconBlinking) {
+ setTimeout(toggleIcon, 1500);
+ iconBlinking = true;
+ }
+ }
+}
+
+/**
+ * Sets the window title after a small delay to prevent race-condition issues.
+ *
+ * @param title
+ * The title to set
+ */
+function setTitle(title) {
+ setTimeout(function() {
+ document.title = title;
+ }, 50);
+}
+
+/** Whether the icon is currently showing activity. */
+var iconActive = false;
+
+/** Whether the icon is currently supposed to blink. */
+var iconBlinking = false;
+
+/**
+ * Toggles the icon. If the window has gained focus and the icon is still
+ * showing the activity state, it is returned to normal.
+ */
+function toggleIcon() {
+ if (focus) {
+ if (iconActive) {
+ changeIcon("images/icon.png");
+ iconActive = false;
+ }
+ iconBlinking = false;
+ } else {
+ iconActive = !iconActive;
+ changeIcon(iconActive ? "images/icon-activity.png" : "images/icon.png");
+ setTimeout(toggleIcon, 1500);
+ }
+}
+
+/**
+ * Changes the icon of the page.
+ *
+ * @param iconUrl
+ * The new URL of the icon
+ */
+function changeIcon(iconUrl) {
+ $("link[rel=icon]").remove();
+ $("head").append($("").attr("rel", "icon").attr("type", "image/png").attr("href", iconUrl));
+ $("iframe[id=icon-update]")[0].src += "";
+}
+
+/**
* Creates a new notification.
*
* @param id
@@ -664,23 +1301,158 @@ function createNotification(id, text, dismissable) {
return notification;
}
+/**
+ * Shows the details of the notification with the given ID.
+ *
+ * @param notificationId
+ * The ID of the notification
+ */
+function showNotificationDetails(notificationId) {
+ $("#sone .notification#" + notificationId + " .text").removeClass("hidden");
+ $("#sone .notification#" + notificationId + " .short-text").addClass("hidden");
+}
+
+/**
+ * Deletes the field with the given ID from the profile.
+ *
+ * @param fieldId
+ * The ID of the field to delete
+ */
+function deleteProfileField(fieldId) {
+ $.getJSON("deleteProfileField.ajax", {"formPassword": getFormPassword(), "field": fieldId}, function(data, textStatus) {
+ if (data && data.success) {
+ $("#sone .profile-field#" + data.field.id).slideUp();
+ }
+ });
+}
+
+/**
+ * Renames a profile field.
+ *
+ * @param fieldId
+ * The ID of the field to rename
+ * @param newName
+ * The new name of the field
+ * @param successFunction
+ * Called when the renaming was successful
+ */
+function editProfileField(fieldId, newName, successFunction) {
+ $.getJSON("editProfileField.ajax", {"formPassword": getFormPassword(), "field": fieldId, "name": newName}, function(data, textStatus) {
+ if (data && data.success) {
+ successFunction();
+ }
+ });
+}
+
+/**
+ * Moves the profile field with the given ID one slot in the given direction.
+ *
+ * @param fieldId
+ * The ID of the field to move
+ * @param direction
+ * The direction to move in (âupâ or âdownâ)
+ * @param successFunction
+ * Function to call on success
+ */
+function moveProfileField(fieldId, direction, successFunction) {
+ $.getJSON("moveProfileField.ajax", {"formPassword": getFormPassword(), "field": fieldId, "direction": direction}, function(data, textStatus) {
+ if (data && data.success) {
+ successFunction();
+ }
+ });
+}
+
+/**
+ * Moves the profile field with the given ID up one slot.
+ *
+ * @param fieldId
+ * The ID of the field to move
+ * @param successFunction
+ * Function to call on success
+ */
+function moveProfileFieldUp(fieldId, successFunction) {
+ moveProfileField(fieldId, "up", successFunction);
+}
+
+/**
+ * Moves the profile field with the given ID down one slot.
+ *
+ * @param fieldId
+ * The ID of the field to move
+ * @param successFunction
+ * Function to call on success
+ */
+function moveProfileFieldDown(fieldId, successFunction) {
+ moveProfileField(fieldId, "down", successFunction);
+}
+
//
// EVERYTHING BELOW HERE IS EXECUTED AFTER LOADING THE PAGE
//
+var focus = true;
+
$(document).ready(function() {
/* this initializes the status update input field. */
getTranslation("WebInterface.DefaultText.StatusUpdate", function(defaultText) {
registerInputTextareaSwap("#sone #update-status .status-input", defaultText, "text", false, false);
+ $("#sone #update-status .select-sender").css("display", "inline");
+ $("#sone #update-status .sender").hide();
+ $("#sone #update-status .select-sender button").click(function() {
+ $("#sone #update-status .sender").show();
+ $("#sone #update-status .select-sender").hide();
+ return false;
+ });
$("#sone #update-status").submit(function() {
- text = $(this).find(":input:enabled").val();
- $.getJSON("ajax/createPost.ajax", { "formPassword": getFormPassword(), "text": text }, function(data, textStatus) {
+ button = $("button:submit", this);
+ button.attr("disabled", "disabled");
+ if ($(this).find(":input.default:enabled").length > 0) {
+ return false;
+ }
+ 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());
+ $(this).find(":input[name=text]:enabled").val("").blur();
+ $(this).find(".sender").hide();
+ $(this).find(".select-sender").show();
+ return false;
+ });
+ });
+
+ /* ajaxify the search input field. */
+ getTranslation("WebInterface.DefaultText.Search", function(defaultText) {
+ registerInputTextareaSwap("#sone #search input[name=query]", defaultText, "query", false, true);
+ });
+
+ /* ajaxify input field on âview Soneâ page. */
+ getTranslation("WebInterface.DefaultText.Message", function(defaultText) {
+ registerInputTextareaSwap("#sone #post-message input[name=text]", defaultText, "text", false, false);
+ $("#sone #post-message .select-sender").css("display", "inline");
+ $("#sone #post-message .sender").hide();
+ $("#sone #post-message .select-sender button").click(function() {
+ $("#sone #post-message .sender").show();
+ $("#sone #post-message .select-sender").hide();
+ return false;
+ });
+ $("#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);
+ loadNewPost(data.postId, getCurrentSoneId());
}
});
- $(this).find(":input:enabled").val("").blur();
+ $(this).find(":input[name=sender]").val(getCurrentSoneId());
+ $(this).find(":input[name=text]:enabled").val("").blur();
+ $(this).find(".sender").hide();
+ $(this).find(".select-sender").show();
return false;
});
});
@@ -697,67 +1469,43 @@ $(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. */
- getTranslation("WebInterface.ClickToShow.Replies", function(text) {
- $("#sone .post .replies").each(function() {
- allReplies = $(this).find(".reply");
- if (allReplies.length > 2) {
- newHidden = false;
- for (replyIndex = 0; replyIndex < (allReplies.length - 2); ++replyIndex) {
- $(allReplies[replyIndex]).addClass("hidden");
- newHidden |= $(allReplies[replyIndex]).hasClass("new");
- }
- clickToShowElement = $("").addClass("click-to-show");
- if (newHidden) {
- clickToShowElement.addClass("new");
+ if (!isViewPostPage()) {
+ getTranslation("WebInterface.ClickToShow.Replies", function(text) {
+ $("#sone .post .replies").each(function() {
+ allReplies = $(this).find(".reply");
+ if (allReplies.length > 2) {
+ newHidden = false;
+ for (replyIndex = 0; replyIndex < (allReplies.length - 2); ++replyIndex) {
+ $(allReplies[replyIndex]).addClass("hidden");
+ newHidden |= $(allReplies[replyIndex]).hasClass("new");
+ }
+ clickToShowElement = $("").addClass("click-to-show");
+ if (newHidden) {
+ clickToShowElement.addClass("new");
+ }
+ (function(clickToShowElement, allReplies, text) {
+ clickToShowElement.text(text);
+ clickToShowElement.click(function() {
+ allReplies.removeClass("hidden");
+ clickToShowElement.addClass("hidden");
+ });
+ })(clickToShowElement, allReplies, text);
+ $(allReplies[0]).before(clickToShowElement);
}
- (function(clickToShowElement, allReplies, text) {
- clickToShowElement.text(text);
- clickToShowElement.click(function() {
- allReplies.removeClass("hidden");
- clickToShowElement.addClass("hidden");
- });
- })(clickToShowElement, allReplies, text);
- $(allReplies[0]).before(clickToShowElement);
- }
+ });
});
- });
+ }
- /*
- * convert all âfollowâ, âunfollowâ, âlockâ, and âunlockâ links to something
- * nicer.
- */
- $("#sone .follow").submit(function() {
- var followElement = this;
- $.getJSON("ajax/followSone.ajax", { "sone": getSoneId(this), "formPassword": getFormPassword() }, function() {
- $(followElement).addClass("hidden");
- $(followElement).parent().find(".unfollow").removeClass("hidden");
- });
- return false;
- });
- $("#sone .unfollow").submit(function() {
- var unfollowElement = this;
- $.getJSON("ajax/unfollowSone.ajax", { "sone": getSoneId(this), "formPassword": getFormPassword() }, function() {
- $(unfollowElement).addClass("hidden");
- $(unfollowElement).parent().find(".follow").removeClass("hidden");
- });
- return false;
- });
- $("#sone .lock").submit(function() {
- var lockElement = this;
- $.getJSON("ajax/lockSone.ajax", { "sone" : getSoneId(this), "formPassword" : getFormPassword() }, function() {
- $(lockElement).addClass("hidden");
- $(lockElement).parent().find(".unlock").removeClass("hidden");
- });
- return false;
- });
- $("#sone .unlock").submit(function() {
- var unlockElement = this;
- $.getJSON("ajax/unlockSone.ajax", { "sone" : getSoneId(this), "formPassword" : getFormPassword() }, function() {
- $(unlockElement).addClass("hidden");
- $(unlockElement).parent().find(".lock").removeClass("hidden");
- });
- return false;
+ $("#sone .sone").each(function() {
+ ajaxifySone($(this));
});
/* process all existing notifications, ajaxify dismiss buttons. */
@@ -767,4 +1515,13 @@ $(document).ready(function() {
/* activate status polling. */
setTimeout(getStatus, 5000);
+
+ /* reset activity counter when the page has focus. */
+ $(window).focus(function() {
+ focus = true;
+ resetActivity();
+ }).blur(function() {
+ focus = false;
+ })
+
});