Sunday, September 17, 2006

Collapsable Posts

Ramani at Hackosphere published a great hack on expandable posts, that expand on the Blog main page. Building on this excellent work, I developed this hack to expand and collapse posts.

As you can see in this post, it starts with only the summary, followed by the 'Read more...' link. Clicking the link expands to the full post. Now at the bottom you will find a 'Summary only...' link, that collapses the post back to its summary.

If you want to know how this hack works, first check out the original hack at Hackosphere.
My hack works along exactly the same lines, with some code added.

Step 1:
Add the following javascript functions to the head of your template:

<script type='text/javascript'>
function showFullPost(id) {
post = document.getElementById(id);
var fullpost = post.getElementsByTagName('div');
if (fullpost.length != 0) {
fullpost[0].style.display = 'inline';
fullpost[1].style.display = 'none';
fullpost[2].style.display = 'inline';
}
}
function hideFullPost(id) {
post = document.getElementById(id);
var fullpost = post.getElementsByTagName('div');
if (fullpost.length != 0) {
fullpost[0].style.display = 'none';
fullpost[1].style.display = 'inline';
fullpost[2].style.display = 'none';
}
}
</script>


Step 2:

Find the includable named 'post' in your template, and change it so that it is exactly as shown below (the code in red has to be added):

<b:includable id='post' var='post'>
<div class='post'>
<a expr:name='data:post.id'/>
<b:if cond='data:post.title'>
<h3 class='post-title'>
<b:if cond='data:post.url'>
<a expr:href='data:post.url'><data:post.title/></a>
<b:else/>
<data:post.title/>
</b:if>
</h3>
</b:if>
<div class='post-header-line-1'/>

<div class='post-body'
 expr:id='"post-" + data:post.id'>
<b:if cond='data:blog.pageType == "item"'>
<p><data:post.body/></p>
<b:else/>
<style>#fullpost {display:none;}</style>
<p><data:post.body/></p>
<div>
<p><a expr:onclick='"javascript:showFullPost(\"post-" + data:post.id + "\");"' href='javascript:void(0);'>Read More...</a></p>
</div>
<div style='display:none'>
<p><a expr:onclick='"javascript:hideFullPost(\"post-" + data:post.id + "\");"' href='javascript:void(0);'>Summary only...</a></p>
</div>
</b:if>
<div style='clear: both;'/> <!-- clear for photos floats -->
</div>
</div>
.... rest of template code ....


Save your template.

Step 3:
In the Settings - Formatting tab go to the bottom and enter the following post-template:

Type your summary here.
<div id="fullpost">
Type the rest of your post here.
</div>

How it works (skip this if you don't like tech stuff).
The changes you made to the code make that every post-body consists of 3 div's: the fullpost-div that you entered in the post-template, a div for the 'Read more'-link, and a div for the 'Summary only'-link.
When you open your blog on the main page, the post is displayed as follows:


  • Summary is displayed (always)

  • Full text is hidden (first div, set to display:none)

  • Read more is shown (second div)

  • Summary only is hidden (third div, set to display:none)

The post is given a unique id, and this id is passed to the javascript-functions showFullPost and hideFullPost respectively. These functions use the getElementsByTagName-methods to obtain handles to the 3 divs, and then toggle the way they are displayed.
Once I understood how Ramani had done the trick, it was easy to expand on his work.

Next steps.
It should also be possible to have posts without a summary. I'll try to get that done soon.