Blog

Revenge of the node comments: a pure jQuery comment pager

Written by Metal Toad Staff | Mar 30, 2010 12:00:00 AM
Filed under:

A previous post described how to reposition node comments with Drupal's hook_menu_alter(), to facilitate a tabbed interface. One side effect that popped up was pagers – when a pager link was clicked, the tab state got reset. The solution was to refresh the #comments div with AJAX. As an interesting twist, it uses the ability of jQuery's $() to construct a new DOM object from HTML. This means that no new menu callback is needed in Drupal; it fetches the comments directly from the href in the pager link. While a little inefficient, this technique has the cool benefit of being able to grab any content from anywhere on your site, with merely a URL and a selector. It also degrades gracefully for non-javascript users; since without JS the tabs appear as sequential blocks the pager will function normally.

(The following code is based on the AJAX Comments project).

/**
 * Attaches the ahah behavior to each ahah form element.
 */
Drupal.behaviors.ajax_comments_pager = function(context) {
  $('#comments .pager:not(.pager-processed)', context).addClass('pager-processed').each(
    function() {
    $target = $(this);
    $target
      .find('li > a')
      .click(function () {
        $(this).animate({paddingRight:16}, 'fast').addClass('throbber').removeAttr('style');
        Drupal.turn_over_page($target, $(this).attr('href'), true, function(){}, function(){
          $(this).removeClass('throbber');
        });
        return false;
      });
  });
}
 
/**
 * Turn over a single page.
 *
 *   @param target
 *     The .pager element.
 *   @param url
 *     New page URL.
 *   @param scroll
 *     Is scroll to comments header needed.
 *   @param success_callback
 *     Function which will be called after pagination
 *     (or immediately if pager does not exists).
 *   @param error_callback
 *     Function which will be called on AJAX error.
 */
Drupal.turn_over_page = function(target, url, scroll, success_callback, error_callback) {
  if (target.length && url) {
    ajaxPath = url;
    $.ajax({
      url: ajaxPath,
      type: 'GET',
      success: function(response) {
        $newComments = $(response).find('#comments');
        $("#comments").replaceWith($newComments);
        Drupal.attachBehaviors($newComments.parent());
        if (scroll) {
          offset = $('#product-tabs').offset();
          $('html,body').animate({scrollTop: offset.top});
        }
      },
      error: function() {
        error_callback();
        alert(Drupal.t("An error occurred at @path.", {'@path': ajaxPath}));
      },
      dataType: 'html'
    });
  }
  else {
    success_callback();
  }
}