jQuery Comments v1.0.4

jQuery Plugn Macros

Change log:

  • Support reply feature. Now user can reply other user's comment

 

Configuration

Name Type Description
pageUrl String The url of the resource to add comments to. Must end with a slash
streamSelector String

The selector of stream wrapper which wraps all comments

renderCommentFn Function The callback function to render the markup for a comment. Takes the following arguments user, comment, commentDate, where user is an object containing name, href, photoHref
clearContainerFn Function The callback function to clear the comments container. Takes no arguments
ajaxLoadingFn Function The callback function to show ajax loading. Takes one argument isLoading (true/false)
commentsPerPage Number The number of comments will be showed per page
paginateFn Function The callback function to render the markeup for pagination
passwordProperty String Property name to use in sending password to server
aggregated Boolean  If true will list all comments under the given page 
afterCommentFn Function The callback will be called after user write a comment
afterReplyFn Function The callback will be called after user reply a comment

 

Default Configuration

{
    pageUrl: window.location,
    streamSelector: '.comments-stream',
    commentTextSelector: '#postQuestion',
    renderCommentFn: function(commentData, config, container) {
        flog('renderCommentFn-104-standard', 'commentData=', commentData, 'container=', container);

        var user = commentData.user;
        var date = new Date(commentData.date);
        var commentText = commentData.comment;
        var commentId = commentData.id;
        var parentId = commentData.parentId;
        var outerDiv = $('#' + commentId);

        if (outerDiv.length === 0) {
            var commentStream = container.find(config.streamSelector);
            var parentComment = $('#' + parentId);
            var isReply = false;
            if (parentComment.length > 0) {
                commentStream = parentComment;
                isReply = true;
            }
            flog('Append new comment block to: ', commentStream, "Selector: ", config.streamSelector);

            var commentString = '';

            // User's name and profile picture
            var commentUserString = '';
            if (user !== null && typeof user !== 'undefined') {
                var profilePic = profileImg(user);
                commentUserString += '<a class="profilePic comment-user-pic" href="' + user.href + '">' + profilePic + '</a>';
                commentUserString += '<a class="user comment-user-name" href="' + user.href + '">' + user.name + '</a>';
            } else {
                commentUserString += '<span class="comment-user-pic profilePic"><img src="/templates/apps/user/profile.png" alt="Anonymous" /></span>';
                commentUserString += '<span class="user comment-user-name">Anonymous</span>';
            }
            commentString += '<div class="comment-user">';
            commentString += commentUserString;
            commentString += '</div>';

            // Comment content and time
            var commentDetailString = '';

            // Comment text
            commentDetailString += '<p class="comment-content cmt">' + commentText + '</p>';

            // Comment reply button
            if (!isReply) {
                commentDetailString += '<a class="comment-reply small" href="#">Reply</a>';
            }

            // Comment datetime
            flog('Comment datetime: ', date);
            var dt = {
                date: date.getDate(),
                month: date.getMonth(),
                year: date.getYear(),
                hour: date.getHours(),
                minute: date.getMinutes()
            };
            commentDetailString += '<abbr title="' + date.toISOString() + '" class="comment-time auxText small text-muted">' + toDisplayDateNoTime(dt) + '</abbr>';

            // Reply for comment
            if (!isReply) {
                commentDetailString += '<div class="comment-replies-wrapper" style="display: none;">';
                commentDetailString += '    <div class="comment-replies"></div>';
                commentDetailString += '    <textarea class="form-control input-sm comment-reply-text" rows="1" data-parentid="' + commentId + '" placeholder="Write a reply..."></textarea>';
                commentDetailString += '    <div class="text-right">';
                commentDetailString += '        <button type="button" class="btn btn-xs btn-info comment-reply-send">Send</button>';
                commentDetailString += '    </div>';
                commentDetailString += '</div>';
            }

            // Comment comment detail block
            commentString += '<div class="comment-detail">';
            commentString += commentDetailString;
            commentString += '</div>';

            // Append comment block to comment stream
            var commentClass = 'forumReply comment';
            if (isReply) {
                commentClass = 'comment comment-sub col-md-offset-1';
            }
            commentStream.append(
                '<div class="' + commentClass + '" id="' + commentId + '">' + commentString + '</div>'
            );
            outerDiv = $('#' + commentId);

            // Event handle for reply text
            var btnReply = outerDiv.find('.comment-reply');
            var replyWrapper = outerDiv.find('.comment-replies-wrapper');

            btnReply.on('click', function(e) {
                e.preventDefault();

                if (replyWrapper.is(':visible')) {
                    replyWrapper.hide();
                } else {
                    replyWrapper.show();
                }
            });

            var btnSendReply = outerDiv.find('.comment-reply-send');
            var txtReplyText = outerDiv.find('.comment-reply-text');

            btnSendReply.on('click', function(e) {
                e.preventDefault();

                var replyText = txtReplyText.val().trim();

                if (replyText) {
                    flog('Submit reply text:', replyText);
                    var replyInput = outerDiv.find('textarea.comment-reply-text');
                    sendCommentReply(config.pageUrl, replyInput, replyInput.data('parentid'), config.renderCommentFn, config.currentUser, config, container);
                    replyWrapper.hide();
                }
            });
        } else {
            flog('Update existing comment');

            // Just update
            outerDiv.find('.cmt, .comment-content').html(commentText);
        }

        jQuery('abbr.auxText, .comment-time', outerDiv).timeago();
    },
    clearContainerFn: function(config, container) {
        container.find(config.streamSelector).html('');
    },
    ajaxLoadingFn: function(isLoading) {
        if (isLoading) {
            ajaxLoadingOn();
        } else {
            ajaxLoadingOff();
        }
    },
    itemsPerPage: 10,
    paginateFn: function(comments, config, container) {
        flog('paginateFn-104-standard', comments, config, container);

        var totalComments = 0;
        for (var i = 0; i < comments.length; i++) {
            var comment = comments[i];

            if (!comment.parentId) {
                totalComments++;
            }
        }
        var itemsPerPage = config.itemsPerPage;

        if (totalComments > itemsPerPage) {
            container.prepend(
                '<div class="well well-sm text-center">' +
                '    <a href="" class="btn-show-more">Show previous comments</a>' +
                '</div>'
            );

            var commentWrappers = container.find('.comment').not('.comment-sub');

            // Show 10 last comments
            commentWrappers.filter(':lt(' + (totalComments - itemsPerPage) + ')').hide().addClass('hidden-comment');

            container.find('.btn-show-more').click(function(e) {
                e.preventDefault();

                var hiddenCommentWrappers = commentWrappers.filter('.hidden-comment');
                var totalHiddenComments = hiddenCommentWrappers.length;

                hiddenCommentWrappers.filter(':gt(' + (totalHiddenComments - itemsPerPage - 1) + ')').show().removeClass('hidden-comment');

                if (totalHiddenComments <= itemsPerPage) {
                    $(this).parent().hide();
                }
            });
        }
    },
    aggregated: false, // if true will list all comments under the given page,
    afterCommentFn: function(commentData, config, container) {
        flog('afterCommentFn-104-standard', commentData, config, container);
    },
    afterReplyFn: function(commentData, config, container) {
        flog('afterReplyFn-104-standard', commentData, config, container);
    }
}