css/javascript footnotes

With the release of rsscms, I wanted to duplicate the footnotes that I have here in WordPress. Thanks to the magic of scriptaculous and prototype – it is relatively easy to do.

As always with any JavaScript related solution, it also needs to be backwards compatible with those users who have turned off, or have been forced to turn off JavaScript.

So a quick bit of code and css leaves us with the following:

Footnotes with JavaScript disabled

Footnotes with JavaScript disabled

With the following code in a common.js file:


function formatContent() {
  // find (span class="footnote") and format the footnotes
  var footnoteArray = $$('span.footnote');
  if(footnoteArray.size() >= 1) {
    // insert new heading element for the footnotes

    var footnoteElement = new Element('div', {'id': 'footnote'})
        .insert(new Element('h3').update('Footnotes:'));
    
    // create the ordered list
    var orderedList = new Element('ol');
    
    // counter
    var offset = 1;
    footnoteArray.each(function(item) {
      // create the marker and the return link
      var returnLink = new Element('a', {'href': '#footnote-marker-' + offset, 'class': offset}).update('(back)');
      returnLink.observe('click', function(event) {
        var footnoteNumber = Event.element(event).classNames(); 
        Effect.ScrollTo('footnote-marker-' + footnoteNumber, {offset: -20}); 
        new Effect.Highlight('footnote-marker-' + footnoteNumber, {duration: 5}); 
        return false;
      });

      var listItem = (new Element('li', {'id': 'footnote-' + offset})
          .update(item.innerHTML)).insert({'bottom':returnLink});

      orderedList.insert(listItem);

      // add in the marker
      var footnoteMarkerLink = new Element('a', {'href': '#footnote-' + offset, 'class': offset})
        .update('[' + offset + ']');
      
      footnoteMarkerLink.observe('click', function(event) {
        var footnoteNumber = Event.element(event).classNames(); 
        Effect.ScrollTo('footnote-' + footnoteNumber, {offset: -20}); 
        new Effect.Highlight('footnote-' + footnoteNumber, {duration: 5}); 
        return false;
      });
      
      var footnoteMarker = new Element('sup', {'id': 'footnote-marker-' + offset})
          .insert(footnoteMarkerLink);
      item.replace(footnoteMarker);
      offset++;
    });
    
    // add it all together
    footnoteElement.insert(orderedList);
    Try.these(
      function() { $('content').insert( {bottom: footnoteElement}) },
      function() { $('content-home').insert( {bottom: footnoteElement})}
    )
      
  }
}



// on window load - format the content
Event.observe(window, 'load', function(event) { formatContent() });

This will loop through all of the span elements that are of class ‘footnote’ and insert them at the bottom of the div with id of ‘content’ or ‘content-home’.

Scriptaculous has a wonderful feature Try.these() which will iterate through the functions. If the first function fails, the next will be attempted until it finds one that returns normally. In the above example you can see that I try to insert the footnotes into the div id=content first (which is the majority of the pages), if this doesn’t work, the div id=content-home is tried which is only on the home page. This saves the testing of elements to see whether they exist.

For larger numbers of templates, an Array should have been set up and then iterated through, rather than cutting and pasting each line of code for each template. Nevertheless, as there are only two templates – probably overkill – but it is in the back of my mind.

The final footnotes look like the following:

JavaScript Enabled Footnote Marker

JavaScript Enabled Footnote Marker

With the footnote nicely placed at the bottom of the correct div:

JavaScript Enabled Footnote

JavaScript Enabled Footnote

As a side note, I am not really sure why anybody would write any JavaScript without at least Prototype or jQuery. They make DOM traversal easy – and make JavaScript ‘Just Work’ over a wide range of browsers.


Leave a Reply

You must be logged in to post a comment.