mourningdove/htdocs/js/jquery.threadexpander.js

222 lines
6.9 KiB
JavaScript
Raw Normal View History

2026-05-24 01:03:05 +00:00
/*
* This handles the thread expansion for comments. It also handles
* the show/hide functionality for comments.
*/
(function($) {
// makes the given comment element displayed fully.
function setFull(commentElement, full) {
commentElement.parent()
.toggleClass("full", full)
.toggleClass("partial", !full);
}
// Returns the talkids of all comments that are replies to this talkid,
// plus the given talkid if includeSelf is called.
function getReplies(LJ, talkid, includeSelf) {
var returnValue = [];
if (includeSelf) {
returnValue.push(talkid);
}
if (LJ[talkid] && LJ[talkid].rc) {
for (var i = 0; i < LJ[talkid].rc.length; i++) {
returnValue = returnValue.concat(getReplies(LJ, LJ[talkid].rc[i], true));
}
}
return returnValue;
}
/**
* Returns all of the unexpanded comments on this page.
*/
function getUnexpandedComments(LJ) {
var returnValue = [];
for (var talkid in LJ) {
if (LJ[talkid].hasOwnProperty("full") && ! LJ[talkid].full && ! LJ[talkid].deleted && (!LJ[talkid].screened || LJ.canAdmin)) {
returnValue.push(talkid);
}
}
return returnValue;
}
// shows an error. just uses alert() for now.
function showExpanderError(element,error) {
$(element).ajaxtip().ajaxtip( "error", error );
}
// ajax expands the comments for the given talkid
$.fn.expandComments = function(LJ, expand_url, talkid, unhide) {
element = this;
// if we've already been clicked, just return.
if (element.hasClass("disabled")) {
return;
}
if (!LJ) {
return false;
}
element.addClass("disabled");
element.fadeTo("fast", 0.5);
var xhr = $.ajax( { url: expand_url,
datatype: "html",
timeout: 30000,
success: function(data) {
var updateCount = element.doJqExpand(LJ, data, talkid, unhide);
// if we didn't update any comments, something must have gone wrong
if (updateCount == 0) {
showExpanderError(element,$.threadexpander.config.text.error_nomatches);
element.removeClass("disabled").fadeTo("fast", 1.0);
} else if (unhide) {
element.unhideComments(LJ, talkid);
}
// remove the expand_all option if all comments are expanded
var expand_all_span = $('.expand_all');
if (expand_all_span.length > 0) {
if (getUnexpandedComments(LJ).length == 0) {
expand_all_span.fadeOut('fast');
} else if (talkid < 0) {
element.removeClass("disabled").fadeTo("fast", 1.0);
}
}
},
error: function(jqXHR, textStatus, errorThrown) {
element.removeClass("disabled");
element.fadeTo("fast", 1.0);
showExpanderError(element,$.threadexpander.config.text.error);
}
} );
$(element).throbber( xhr );
};
// callback to handle comment expansion
$.fn.doJqExpand = function(LJ, data, talkid, unhide) {
var updateCount = 0;
// check for matching expansions on the page
var replies;
if (talkid > 0) {
replies = getReplies(LJ, talkid, true);
} else {
replies = getUnexpandedComments(LJ);
}
if (replies.length > 0) {
// get all comments and map them by id. this seems to be more efficient
// in jquery (at least for the results of an ajax request).
var newComments = $(".dwexpcomment", data);
var newCommentMap = {};
newComments.each(function() {
newCommentMap[$(this).attr("id")] = $(this);
});
for (var cmtIdCnt = 0; cmtIdCnt < replies.length; cmtIdCnt++) {
var cmtId = replies[cmtIdCnt];
// if we're a valid comment, and either the comment is not expanded
// or it's the original comment, then it's valid to expand it.
if (/^\d*$/.test(cmtId) && (talkid == cmtId || (! LJ[cmtId].full))) {
var cmtElement = $('#cmt' + cmtId);
if (cmtElement.length > 0) {
var newComment = newCommentMap["cmt" + cmtId];
// if there's no match, check the (slower) way.
if (! newComment) {
newComment = $("#cmt" + cmtId, data);
}
if (newComment) {
cmtElement.html($(newComment).html())
.trigger( "updatedcontent.comment" );
$(".cmt_show_hide_default", cmtElement).show();
// don't mark partial comments as full; make sure that the
// loaded comments are full.
if (newComment.find(".full").length > 0) {
LJ[cmtId].full = true;
setFull(cmtElement, true);
}
updateCount++;
}
}
}
}
}
return updateCount;
}
// returns the comment elements for the given talkids.
function getReplyElements(replies) {
var returnValue = [];
for (var cmtIdCnt = 0; cmtIdCnt < replies.length; cmtIdCnt++) {
var cmtId = replies[cmtIdCnt];
if (/^\d*$/.test(cmtId)) {
var cmtElement = $("#cmt" + cmtId);
returnValue.push(cmtElement);
}
}
return returnValue;
}
// hides all the comments under this comment.
$.fn.hideComments = function(LJ, talkid) {
var replies = getReplies(LJ, talkid, false);
var replyElements = getReplyElements(replies);
for (var i = 0; i < replyElements.length; i++) {
replyElements[i].slideUp("fast");
}
$("#cmt" + talkid + "_hide").hide();
$("#cmt" + talkid + "_unhide").show();
}
// shows all the comments under this comment.
$.fn.unhideComments = function(LJ, talkid) {
var replies = getReplies(LJ, talkid, false);
var replyElements = getReplyElements(replies);
for (var i = 0; i < replyElements.length; i++) {
// we're revealing the entire tree, so the subcomments should
// all show the hide option, not the unhide option.
$(".cmt_hide", replyElements[i]).show();
$(".cmt_unhide", replyElements[i]).hide();
replyElements[i].slideDown("fast");
}
// and this comment itself should show hide.
$("#cmt" + talkid + "_hide").show();
$("#cmt" + talkid + "_unhide").hide();
}
// reveal all hide links on document ready, so we don't have them if
// we don't have javascript enabled.
$(document).ready(function() {
$(".cmt_show_hide_default").show();
});
$.threadexpander = {
config: {
text: {
error: "Error: no response while expanding comments.",
error_nomatches: "Error: no comments found to expand."
}
}
};
})(jQuery);
// globals for backwards compatibility
Expander = {
make: function(element, url, dtid, unhide) {
$(element).expandComments(LJ_cmtinfo, url, dtid, unhide);
},
hideComments: function(element, dtid) {
$(element).hideComments(LJ_cmtinfo, dtid);
},
unhideComments: function(element, dtid) {
$(element).unhideComments(LJ_cmtinfo, dtid);
}
};