Update (200911-08): I’ve stopped using this, because it made the archive generating fail in mysterious ways…

As you might have seen I have now these nice (opinions may vary) “more…” links in my blog. This is done with some JavaScript and shell foo and in this entry I will explain how I did it.

The setup also works with text browsers and people who disable JavaScript. In the latter case you will get the normal nb behavior where you see the entire article. When using a text browser you also see the entire article but there is also a (non functional) ‘more’ link.

User side

When writing a blog entry the only thing you need to do is to put the following on a line

- read more -

(technically you need more -’s to make it work, but this will suffice for this example).

Anything you type below that line will become collapsible with a ‘more’ link. Anything above will be directly visible.

Implementation First a shell script which reads your entire blog entry and replaces the - read more- with the html and JavaScript to make it work.

#!/bin/bash
EPOCH=$(date +%s)
ART_ID="art_$$_$EPOCH"
HREF_ID="href_$$_$EPOCH"
DATA=$(cat)

# escape galore
repl="<script type=\"text\/javascript\">\n\
<!--\n\
function toggle_visibility(id, anchor) {\n\
   var e = document.getElementById(id);\n\
   var a = document.getElementById(anchor);\n\
   if(e.style.display == 'block') {\n\
      e.style.display = 'none';\n\
      a.innerHTML = \"\&laquo; more ...\";\n\
   } else {\n\
      e.style.display = 'block';\n\
      a.innerHTML = \"\&laquo; less\";\n\
   }\n\
}\n\
\/\/-->\n\
<\/script>\n\
<div class=\"readmore\">\n\
<a class=\"readmore\" style=\"display: none;\" id=\"$HREF_ID\"\n\
href=\"javascript:\/\/\" onclick=\"toggle_visibility(\'$ART_ID\', \'$HREF_ID\');\">\
\&raquo; more ...<\/a>\n\
<\/div>\n\
<div id=\"$ART_ID\">\n\
<script type=\"text\/javascript\">\n\
<!--\n\
e = document.getElementById('$ART_ID');\n\
e.style.display = 'none';\n\
e = document.getElementById('$HREF_ID');\n\
e.style.display = 'block';\n\
\/\/-->\n\
<\/script>\n\
"
if echo "$DATA" | egrep -q -- '-{3,}.?read.more.?-{3,}'; then
echo "$DATA" | sed -r "s/-{3,}.?read.more.?-{3,}/$repl/"
echo "</div> <!-- id=$ART_ID -->";
else
echo "$DATA"
fi

As I’m using stdin twice I am capturing it in the variable $DATA.

The variable $repl is filled and is used by sed the replace - read more-. It was a real pain to correctly quote everything (as you might see).

The JavaScript trick to do this collapsing can be easily found on the internet (google: hide/show divs).

interfacing with nanobloggger

You need to edit two templates, entry.htm and permalink.htm, in the first one you enable the ‘read more’-feature and the latter you need to get rid of the ‘- read more -’ line.

entry.htm

In entry.htm replace

$NB_EntryBody

with

$(echo "$NB_EntryBody" | ${BLOG_DIR}/bin/readmore)

Adjust this to where you have saved the shell script from above.

permalink.htm

On your permalink page this read more stuff is ridiculous, so there we must get rid of it.

Where it says

$NB_EntryBody

replace that with

$(echo "$NB_EntryBody" | sed -r 's/-{3,}.?read.more.?-{3,}//')

to filter out the line.