Skip to content

Melody Cookbook: Comment pagination with jQuery

mikert edited this page Feb 26, 2011 · 1 revision

Prerequisites

  1. Basic familiarity with JavaScript.
  2. Basic familiarity with Melody tags.
  3. Some knowledge of jQuery or a willingness to learn it as you go.

Config.yaml Settings

Under the options branch of your theme, add the following two options:

paginate_comments_enable:
    label: Enable Comment Pagination
    hint: If checked, comments will be paginated.
    type: checkbox
    tag: 'SampleThemeCommentPaginationEnabled?'

paginate_comments_count:
    label: Comments Per Page
    hint: If pagination is enabled, this is how many comments appear on one page.
    type: text
    tag: SampleThemeCommentsPerPage

The first one creates a conditional tag that can be used like this in a theme when you need to do something based on whether or not comments are paginated:

<mt:SampleThemeCommentPaginationEnabled>
    <$mt:SampleThemeCommentsPerPage setvar="commentsPerPage"$>
    ...
<mt:Else>
    ...
</mt:SampleThemeCommentPaginationEnabled>

Templates

Comment Templates

You are going to need two templates:

  1. A module called "Comment Detail."
  2. A system template named "Comment Listing."

The code for the comment listing template is:

{
    "direction": "<mt:Var name="commentDirection">",
    "comments": "<mt:Comments sort_order="$commentDirection"><$mt:Include identifier="comment_detail" replace="\","\\" replace='"','\"' strip_linefeeds="1"$></mt:Comments>"
}

Here is a sample for comment detail. It is from the original classic blog templates. It is intended to be an example of how this works, not something for you to copy and paste in its current form.

<div id="comment-<$mt:CommentID$>" class="comment<mt:IfCommentParent> comment-reply</mt:IfCommentParent><mt:IfCommenterIsEntryAuthor> entry-author-comment</mt:IfCommenterIsEntryAuthor>">
    <div class="inner">
        <div class="comment-header">
            <div class="asset-meta">
                <span class="byline">
                    <$mt:CommentAuthorIdentity$>
<mt:IfCommentParent>
                    <__trans phrase="[_1] replied to <a href="[_2]">comment from [_3]</a>" params="<span class="vcard author"><$mt:CommentAuthorLink$></span>%%<mt:CommentParent><$mt:CommentLink$></mt:CommentParent>%%<mt:CommentParent><$mt:CommentAuthor$></mt:CommentParent>">
<mt:Else>
                    <span class="vcard author"><$mt:CommentAuthorLink$></span>
</mt:IfCommentParent>
                    | <a href="<$mt:CommentLink$>"><abbr class="published" title="<$mt:CommentDate format_name="iso8601"$>"><$mt:CommentDate$></abbr></a>
<mt:IfCommentsAccepted>
                    | <$mt:CommentReplyToLink$>
</mt:IfCommentsAccepted>
                </span>
            </div>
        </div>
        <div class="comment-content">
            <$mt:CommentBody$>
        </div>
    </div>
</div>

Save yours files respectively as:

  1. comment_listing.mtml
  2. comment_detail.mtml

Entry Template

Add the following MTML to your entry templates to do a basic listing of comments that is ready for pagination.

<mt:SampleThemeCommentPaginationEnabled>
    <$mt:SampleThemeCommentsPerPage setvar="commentsPerPage"$>
    <mt:Comments lastn="$commentsPerPage">
        <$mt:Include identifier="comment_detail"$>
    </mt:Comments>
    <div id="navigation">
        <div class="left">
             <a href="#comments" id="a-prev" style="display: none"><__trans phrase="&laquo; Older Comments"></a>
        </div>
        <div class="right">
             <a href="#comments" id="a-next" ><__trans phrase="Newer Comments &raquo;"></a>
        </div>
    </div>
<mt:Else>
    <mt:Comments>
        <$mt:Include identifier="comment_detail"$>
    </mt:Comments
</mt:SampleThemeCommentPaginationEnabled>

Performance Tip: The Include tag is used in these samples for readability in this tutorial. You should actually consider copying the contents of the comment detail module into the <mt:Comments/> loops.

JavaScript

After the conditional block shown above, add the following MTML and JavaScript to your entry template.

<mt:SampleThemeCommentPaginationEnabled>
<script type="text/javascript">
    var offset = 0;
    var incOffsetBy = <$mt:SampleThemeCommentsPerPage$> ;
    function success(data, status, xhr) {
        $('ol.commentlist').remove();
        $(data.comments).insertAfter( $('#comments') );
    }

    function error(jqXHR, textStatus, errorThrown) {
        alert(textStatus);
    }

    $(function() {
        newer = $('#a-newer').click(function() {
            offset += incOffsetBy;
            $.ajax({
                url: '<$mt:CGIPath$><$mt:CommentScript$>',
                data: {
                    '__mode': 'comment_listing',
                    'entry_id': <$mt:EntryID$>,
                    'direction': 'ascend',
                    'limit': incOffsetBy,
                    'offset': offset
                }
            })
            .success(success)
            .error(error)
            .complete(function() {
                if ( older.is(':hidden'))
                    older.show();
                if ( $('ol.commentlist li').length < incOffsetBy)
                    newer.hide();
            });
        });
        older = $('#a-prev').click(function() {
            offset -= incOffsetBy;
            $.ajax({
                url: '<$mt:CGIPath$><$mt:CommentScript$>',
                data: {
                    '__mode': 'comment_listing',
                    'entry_id': <$mt:EntryID$>,
                    'direction': 'ascend',
                    'limit': incOffsetBy,
                    'offset': offset
                }
            })
            .success(success)
            .error(error).complete(function() {
                if ( newer.is(':hidden') )
                    newer.show();
                if ( offset <= 0 )
                    older.hide();
            });
        });

    });
</script>
</mt:SampleThemeCommentPaginationEnabled>

This example utilizes the jQuery 1.5 AJAX API. It will not work with older versions of jQuery.

The mile-in-the-sky view of what this seeks to do is the following:

  1. Create a reusable JavaScript variable that holds the amount of comments per page. This is to increase publishing performance a little bit.
  2. Since the success/error scenarios are the same for both links, their event handlers are declare in advance to reuse some code.
  3. A document-ready listener is bound, $(function() {});
  4. In the document-ready-listener, the links are found by jQuery and receive click handlers that execute AJAX calls to the comment_listing mode of the comment script.
  5. At the end of each AJAX call, jQuery looks at either the offset or the number of comments returned and if necessary, hides one of the links to prevent a user from clicking on it when they should not.
Clone this wiki locally