Sunday, March 01, 2009

Peekaboo

Hell yes I got peekaboo comments working again!

In the old Blogger, the comments were available from any page, including non-item pages. This is no longer the case, so I couldn't simply hide the comment block like I used to.

BUT! There is now a comment RSS feed for each post. Aha! I read in the feed and write out the comments. Formatting is lost (the feed only includes the bare text), but it works for a peek, and that's what I wanted.

I already had phidden and pshown set up in my style sheet, because I use them to hide videos.

.phidden {display:none}
.pshown {display:inline}


And for the same reason, I already had the javascript functions to use these styles.
function hide (which){
which.className='phidden';
}

function show (which){
which.className='pshown';
}

function hideid (id) {
var which = document.getElementById(id);
which.className='phidden';
}

function showid (id) {
var which = document.getElementById(id);
which.className='pshown';
}

function togglehidden (id) {
var which = document.getElementById(id);

if (which.className=='pshown') {
hide(which);
}
else {
show(which);
}
}
I just needed code to load, parse, and write the rss data in the post loop. Oh no! The DATE information isn't in any format that javascript can recognize! So I have to parse that too.
function parseXSDDateString(dateString) {
var Zp = (dateString.charAt(10) == "T") ? 19 : 10;
if (19 == Zp) {
if ("." == dateString.charAt(19)) {
dateString = dateString.substr(0, 18) + dateString.substr(22);
}
}
var xDate = new Date(dateString.substr(0, Zp).replace(/-/g, '/').replace("T", " "));
if (dateString.length > Zp) {
xDate.setMinutes(xDate.getMinutes() + xDate.getTimezoneOffset());
if (dateString.charAt(Zp) != "Z") {
var tZ = dateString.substr(Zp).split(":");
tZ = tZ[0] * 60 + (tZ[1] * 1);
xDate.setMinutes(xDate.getMinutes() + tZ);
}
}
return xDate;
}

function hideComments(curl) {
var cid = curl.substring(curl.lastIndexOf('=') + 1);
document.write("<a href=\"javascript:togglehidden('c" + cid + "')\">peek</a>");
document.write("<span class=\"phidden\" id=\"c" + cid + "\">");
var xmlDoc = null;
if (window.ActiveXObject) { // code for IE
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
} else if (document.implementation.createDocument) { // code for Mozilla, Firefox, Opera, etc.
xmlDoc = document.implementation.createDocument("", "", null);
} else {
alert('Your browser cannot handle this script');
}
if (xmlDoc != null) {
xmlDoc.async = false;
xmlDoc.load("http://myrighteye.korv.us/feeds/" + cid + "/comments/default");
document.write("<dl id='comments-block'>");
var x = xmlDoc.getElementsByTagName("entry");
for (i = x.length - 1; i >= 0; i--) {
var auth = x[i].getElementsByTagName("author");
var permalink = x[i].getElementsByTagName("link")[2].attributes[2].value;
var id = permalink.substring(permalink.lastIndexOf('#'));
var d = parseXSDDateString(x[i].getElementsByTagName("published")[0].childNodes[0].nodeValue);
document.write("<dt class='comment-author blogger-comment-icon' id='" + id + "'>");
document.write("<a name='" + id + "'></a>");
document.write("<a href='" + auth[0].getElementsByTagName("uri")[0].childNodes[0].nodeValue + "' rel='nofollow'>" + auth[0].getElementsByTagName("name")[0].childNodes[0].nodeValue + "</a> said...");
document.write("</dt>");
document.write("<dd class='comment-body'>");
document.write("<p>" + x[i].getElementsByTagName("summary")[0].childNodes[0].nodeValue + "</p>");
document.write("</dd>");
document.write("<dd class='comment-footer'>");
document.write("<span class='comment-timestamp'>");
document.write("<a href='" + permalink + "' title='comment permalink'>");
document.write(d.toLocaleString());
document.write("</a>");
document.write("</span>");
document.write("</dd>");
}
document.write("</dl>");
}
document.write("</span>");
}
(Yes, it would be more proper not to use document.write but I'm lazy).

Then there was the tricky part: adding the peek link to the post includable. I only want it showing up on the main page and archive pages, not item pages.

(Also, before you do this, if you use the Layout option to edit your post format, do that now; it's going to stop working once you fiddle with its internals)

Expanded the widgets and searched for "data:post.addCommentUrl" (which shows up twice; for separate page and embedded commenting). The first instance looked like:
<b:if cond='data:post.allowComments'>
<a class='comment-link' expr:href='data:post.addCommentUrl' expr:onclick='data:post.addCommentOnclick'><b:if cond='data:post.numComments == 1'>1 <data:top.commentLabel/><b:else/><data:post.numComments/> <data:top.commentLabelPlural/></b:if></a>
</b:if>
I changed this to:
<b:if cond='data:post.allowComments'>
<a class='comment-link' expr:href='data:post.addCommentUrl' expr:onclick='data:post.addCommentOnclick'><b:if cond='data:post.numComments == 1'>1 <data:top.commentLabel/><b:else/><data:post.numComments/> <data:top.commentLabelPlural/></b:if></a>
<b:if cond='data:post.numComments &gt; 0'>
<script type='text/javascript'>
hideComments(&quot;<data:post.addCommentUrl/>&quot;);
</script>
</b:if>

</b:if>
Hurray, success! Or I should say SUCCESS, since there's apparently a text-transform:uppercase in effect. So add text-transform:none; to #comments-block and voila.

So, it's working (and without loaded huge external .js files like other peekaboo comment systems I won't mention), but there is a lot of room for improvement. It's not asynchronous, so every rss feed for every post on the page is retrieved and parsed (potentially SLOW); it COULD retrieve the feed when you click peek, as needed (also, all of my javascript links are way old-style and should be updated to use proper onclick events). I could make proper element creators instead of half-assing with document.write. I could clean up the code a LOT.

But, it's working, so I'm probably not going to do any of that. ^_^

No comments:

Post a Comment