We are using the excellent Blog4Umbraco4 to power the blog you're currently reading, and during the course of building the site we decided it would be nice to have nested/threaded comments to encourage more conversation-like dialogue amongst comments. It turns out that by using a combination of jQuery and Doc2Form this is very easy!
To get started, I switched out the standard Blog4Umbraco4 comment form with Doc2Form, as it allowed me to change the form fields based on the document type without having to do any .NET coding. This can be set to post nodes under the current node by using ChooseWhereToStore="[#pageID]" in the macro properties.
I also added a property called "Reply to" (alias commentReply) to the document type of BlogPostComment added by the blog package. This is what is used to store the node if the comment that is being replied to, so all I then needed to was to write a short bit of javascript to add a "reply to this comment" button on all comments, then prefill the reply form with the ID of the comment to be replied to.
Here's the JQuery being used (this could also easily be done with any other JavaScript framework, or no framework at all).
//Set the value of our commentReply input to be blank, in case user refreshes page and no longer wants to reply
$(".commentReply_li input").val("");
//Add a reply to button at the end of all comments
$(".commentcontent").append("Reply to this comment
");
//when reply button is clicked
$("p.reply_to a").live("click", function(){
//grab the "Commentid-2821" number and trim it to get the nodeID
var replyToNum = $(this).parent().parent().parent("li").attr("id");
replyToNum = replyToNum.slice(8);
//Grab the name of the person being replied to
var replyToName = $(this).parent().parent().parent("li").children(".comment_meta").children("a").text();
//Add a notice showing users who they are replying to
$("#comment_form").prepend("You are replying to "+replyToName+" cancel reply
")
//add the node id to the hidden "commentReply" field (wth cancel button)
$(".commentReply_li input").val(replyToNum)
});
// clear data when cancel link is clicked
$("#comment_form h4 a").live("click", function(){
$(this).parent("h4").fadeOut("slow");
$(".commentReply_li input").val("");
return false;
});
The code above + comments should speak for itself. Basically what we're doing is adding a reply button to every comment that when clicked adds the ID of that comment to the commentReply field (that we have hidden with CSS).
Now when the user posts we know if they are replying to another comment if the commentReply field is filled in, and we can use recursive templates in xslt to display the comments in a nested fashion.
TinyMCEand Umbraco are dying when posting xsl in the editor, so here's a link to the amended BlogPostListComments.xslt. Just comment on this post if you have any questions about this file.
That's pretty much it. I've left out a few bits and pieces here, such as
- Hiding the commentReply field on Doc2Form with CSS
- Replacing the standard comment form with Doc2Form
- Anything else? Comment if you'd like more clarification on anything here
Another example of how flexible umbraco is! You can follow us on twitter.com/geckonm, or myself on twitter.com/allbutlost for the occasional Umbraco titbit.