jquery-comments

jquery-comments is a jQuery plugin for implementing an out-of-the-box commenting solution to any web application with an existing backend. It provides all the UI functionalities and ties them to callbacks that let you easily define what you want to do with the data. The library is highly customizable and very easy to integrate thanks to a wide variety of settings.

Screenshot of jquery-comments

Features

Demo

http://viima.github.io/jquery-comments/demo/

Quick start

1) Add the following to your HTML file

<link rel="stylesheet" type="text/css" href="css/jquery-comments.css">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery-comments.js"></script>

2) Initialize the library

$('#comments-container').comments({
    profilePictureURL: 'https://app.viima.com/static/media/user_profiles/user-icon.png',
    getComments: function(success, error) {
        var commentsArray = [{
            id: 1,
            created: '2015-10-01',
            content: 'Lorem ipsum dolort sit amet',
            fullname: 'Simon Powell',
            upvote_count: 2,
            user_has_upvoted: false
        }];
        success(commentsArray);
    }
});

If you are not using Font Awesome for icons, you should replace the icons with custom images by overriding following options when initializing the library:

spinnerIconURL: '',
noCommentsIconURL: '',
upvoteIconURL: '',      // Only if upvoting is enabled
replyIconURL: '',       // Only if replying is enabled
uploadIconURL: '',      // Only if attachments are enabled
attachmentIconURL: '',  // Only if attachments are enabled
fileIconURL: '',        // Only if attachments are enabled

Configuration options

Current user
profilePictureURL

An url for profile picture of the current user. Not required if Font Awesome is used.

""
$('#comments-container').comments({
    profilePictureURL: '/user_profiles/user-icon.png'
});
currentUserIsAdmin

A boolean value determing whether the current user is administarator

false
$('#comments-container').comments({
    currentUserIsAdmin: true
});
Images
spinnerIconURL

An url for spinner icon that is shown before comments have been fetched. Not required if Font Awesome is used.

""
$('#comments-container').comments({
    spinnerIconURL: '/img/spinner.gif'
});
upvoteIconURL

An url for upvote icon that is used as a button for upvoting. Not required if Font Awesome is used.

""
$('#comments-container').comments({
    upvoteIconURL: '/img/upvote-icon.png'
});
replyIconURL

An url for reply icon that is shown after the author of the comment if the comment is a reply. Not required if Font Awesome is used.

""
$('#comments-container').comments({
    replyIconURL: '/img/reply-icon.png'
});
uploadIconURL

An url for upload icon that is used as a button for uploading attachments. Not required if Font Awesome is used.

""
$('#comments-container').comments({
    uploadIconURL: '/img/upload-icon.png'
});
attachmentIconURL

An url for attachment icon that is used as a symbor for attachments. Not required if Font Awesome is used.

""
$('#comments-container').comments({
    attachmentIconURL: '/img/attachment-icon.png'
});
fileIconURL

An url for file icon that is used to indicate that a link is an attachment. Not required if Font Awesome is used.

""
$('#comments-container').comments({
    fileIconURL: '/img/file-icon.png'
});
noCommentsIconURL

An url for no-comments icon that is shown if there are no comments to show. Not required if Font Awesome is used.

""
$('#comments-container').comments({
    noCommentsIconURL: '/img/no-comments-icon.png'
});
Strings
textareaPlaceholderText

A string that is displayed as a placeholder in commenting fields

"Add a comment"
$('#comments-container').comments({
    textareaPlaceholderText: 'Leave a comment'
});
newestText

A string that is displayed on sorting button for newest comments

"Newest"
$('#comments-container').comments({
    newestText: 'New'
});
oldestText

A string that is displayed on sorting button for oldest comments

"Oldest"
$('#comments-container').comments({
    oldestText: 'Old'
});
popularText

A string that is displayed on sorting button for most popular comments

"Popular"
$('#comments-container').comments({
    popularText: 'Most popular'
});
attachmentsText

A string that is displayed on sorting button for attachments

"Attachments"
$('#comments-container').comments({
    attachmentsText: 'Show attachments'
});
sendText

A string that is displayed on send button

"Send"
$('#comments-container').comments({
    sendText: 'Comment'
});
replyText

A string that is displayed on reply button

"Reply"
$('#comments-container').comments({
    replyText: 'Answer'
});
editText

A string that is displayed on edit button

"Edit"
$('#comments-container').comments({
    editText: 'Modify'
});
editedText

A string that is displayed on edited timestamp

"Edited"
$('#comments-container').comments({
    editedText: 'Modified'
});
youText

A string that is displayed as a name of the user for new comments by default

"You"
$('#comments-container').comments({
    youText: 'Me'
});
saveText

A string that is displayed on save button

"Save"
$('#comments-container').comments({
    saveText: 'Update'
});
deleteText

A string that is displayed on delete button

"Delete"
$('#comments-container').comments({
    deleteText: 'Remove'
});
viewAllRepliesText

A string that is displayed to show all replies when there are more replies than defined in maxRepliesVisible option. Variable __replyCount__ is used as a placeholder for the reply count.

"View all __replyCount__ replies"
$('#comments-container').comments({
    viewAllRepliesText: 'Show all replies (__replyCount__)'
});
hideRepliesText

A string that is displayed to hide replies that weren't visible initially

"Hide replies"
$('#comments-container').comments({
    hideRepliesText: 'Hide'
});
noCommentsText

A string that is displayed if there are no comments to show

"No comments"
$('#comments-container').comments({
    noCommentsText: 'There are no comments'
});
noAttachmentsText

A string that is displayed if there are no attachments to show

"No attachments"
$('#comments-container').comments({
    noAttachmentsText: 'There are no attachments'
});
attachmentDropText

A string that is used to inform the user where the attachments can be dropped

"Drop files here"
$('#comments-container').comments({
    attachmentDropText: 'Drop here'
});
Colors
highlightColor

A css value for the highlight color that is used for example to highlight active sorting button and comments by admin

#337AB7
$('#comments-container').comments({
    highlightColor: '#23A6F0'
});
deleteButtonColor

A css value for the color of the delete button

#C9302C
$('#comments-container').comments({
    deleteButtonColor: 'red'
});
Functionalities
enableReplying

A boolean value determing whether replying is enabled

true
$('#comments-container').comments({
    enableReplying: false
});
enableEditing

A boolean value determing whether editing is enabled

true
$('#comments-container').comments({
    enableEditing: false
});
enableUpvoting

A boolean value determing whether upvoting is enabled

true
$('#comments-container').comments({
    enableUpvoting: false
});
enableDeleting

A boolean value determing whether deleting is enabled

true
$('#comments-container').comments({
    enableDeleting: false
});
enableDeletingCommentWithReplies

A boolean value determing whether user is allowed to delete own comment that has replies (replies will be deleted as well)

true
$('#comments-container').comments({
    enableDeletingCommentWithReplies: false
});
enableAttachments

A boolean value determing whether attachments are enabled

false
$('#comments-container').comments({
    enableAttachments: true
});
enableHashtags

A boolean value determing whether hashtags are enabled. Enabling this functionality highlights the hashtags and the hashtagClicked callback function will be executed once the user has clicked a hashtag.

false
$('#comments-container').comments({
    enableHashtags: true
});
enablePinging

A boolean value determing whether pinging users is enabled. Enabling this functionality highlights the pings and the pingClicked callback function will be executed once the user has clicked a ping.


  • The feature is depended on a javascript library called jquery-textcomplete
  • You need to provide the list of users who can be pinged using the getUsers callback function
  • jquery-comments assumes that the pings are sent to the server in format @<user_id>, for example @145
  • jquery-comments assumes that the pings are returned from the server in format @<user_fullname>, for example @Bryan Connery together with array of pinged user ids in same order they appear in the comment
Switching the ping format is required in order to keep the link between the user model and the ping so that the ping won't get broken in case the user changes her name for example. On the other hand, we expect the server to return the ping in user friendly format so that the API will always return comments in a format that can be displayed without processing.

false
$('#comments-container').comments({
    enablePinging: true
});
enableNavigation

A boolean value determing whether navigation is enabled

true
$('#comments-container').comments({
    enableNavigation: false
});
postCommentOnEnter

A boolean value determing whether comments will be posted by pressing enter

false
$('#comments-container').comments({
    postCommentOnEnter: true
});
forceResponsive

A boolean value determing whether the main navigation elements are presented in a dropdown

false
$('#comments-container').comments({
    forceResponsive: true
});
readOnly

A boolean value determing whether any actions are enabled

false
$('#comments-container').comments({
    readOnly: true
});
Field mappings
fieldMappings

A dictionary that is used to map the fields between jquery-comments and the server. The keys of the dictionary represent field names used within the jquery-comments whereas the values represent the field names from your API. In callback functions the data is remapped to match with your API so you can use the comment data as such.

id                      // Required
parent                  // Required if replying is enabled
created                 // Required
modified                // Required if editing is enabled
content                 // Either content or fileURL must be present
fileURL                 // Either content or fileURL must be present
file                    // Required when uploading an attachment
fileMimeType            // Optional
pings                   // Required if pinging is enabled
creator                 // Required if pinging is enabled
fullname                // Required
profileURL              // Optional
profilePictureURL       // Optional
isNew                   // Optional
createdByAdmin          // Optional
createdByCurrentUser    // Required if editing is enabled
upvoteCount             // Required if upvoting is enabled
userHasUpvoted          // Required if upvoting is enabled
fieldMappings: {
    id: 'id',
    parent: 'parent',
    created: 'created',
    modified: 'modified',
    content: 'content',
    file: 'file',
    fileURL: 'file_url',
    fileMimeType: 'file_mime_type',
    pings: 'pings',
    creator: 'creator',
    fullname: 'fullname',
    profileURL: 'profile_url',
    profilePictureURL: 'profile_picture_url',
    isNew: 'is_new',
    createdByAdmin: 'created_by_admin',
    createdByCurrentUser: 'created_by_current_user',
    upvoteCount: 'upvote_count',
    userHasUpvoted: 'user_has_upvoted'
}
$('#comments-container').comments({
    fieldMappings: {
       parent: 'comment_id',
       modified: 'edited',
       fullname: 'name',
       profilePictureURL: 'user_image',
       upvoteCount: 'upvotes',
    }
});
Callbacks
refresh

A callback function that is called after the comments have been rendered

function() {}
$('#comments-container').comments({
    refresh: function() {
        $('#comments-container').addClass('rendered');
    }
});
getComments

A callback function that is used to fetch the comments array from the server. The callback provides both success and error callbacks which should be called based on the result from the server. The success callback takes the comment array as a parameter.

function(success, error) {
    success([]);
}
$('#comments-container').comments({
    getComments: function(success, error) {
        $.ajax({
            type: 'get',
            url: '/api/comments/',
            success: function(commentsArray) {
                success(commentsArray)
            },
            error: error
        });
    }
});
getUsers

A callback function that is used to fetch the user array from the server. The callback provides both success and error callbacks which should be called based on the result from the server. The success callback takes the user array as a parameter.

function(success, error) {
    success([]);
}
$('#comments-container').comments({
    getUsers: function(success, error) {
        $.ajax({
            type: 'get',
            url: '/api/users/',
            success: function(userArray) {
                success(userArray)
            },
            error: error
        });
    }
});
postComment

A callback function that is used to create a new comment to the server. The first parameter of the callback is commentJSON that contains the data of the new comment. The callback provides both success and error callbacks which should be called based on the result from the server. The success callback takes the created comment as a parameter.

function(commentJSON, success, error) {
    success(commentJSON);
}
$('#comments-container').comments({
    postComment: function(commentJSON, success, error) {
        $.ajax({
            type: 'post',
            url: '/api/comments/',
            data: commentJSON,
            success: function(comment) {
                success(comment)
            },
            error: error
        });
    }
});
putComment

A callback function that is used to update an existing comment to the server. The first parameter of the callback is commentJSON that contains the data of the updated comment. The callback provides both success and error callbacks which should be called based on the result from the server. The success callback takes the updated comment as a parameter.

function(commentJSON, success, error) {
    success(commentJSON);
}
$('#comments-container').comments({
    putComment: function(commentJSON, success, error) {
        $.ajax({
            type: 'put',
            url: '/api/comments/' + commentJSON.id,
            data: commentJSON,
            success: function(comment) {
                success(comment)
            },
            error: error
        });
    }
});
deleteComment

A callback function that is used to delete a comment from the server. The first parameter of the callback is commentJSON that contains the data of the comment to be deleted. The callback provides both success and error callbacks which should be called based on the result from the server.

function(commentJSON, success, error) {
    success();
}
$('#comments-container').comments({
    deleteComment: function(commentJSON, success, error) {
        $.ajax({
            type: 'delete',
            url: '/api/comments/' + commentJSON.id,
            success: success,
            error: error
        });
    }
});
upvoteComment

A callback function that is used to create or delete an upvote. The first parameter of the callback is commentJSON that contains the data of the upvoted comment. The callback provides both success and error callbacks which should be called based on the result from the server. The success callback takes the updated comment as a parameter.

function(commentJSON, success, error) {
    success(commentJSON);
}
$('#comments-container').comments({
    upvoteComment: function(commentJSON, success, error) {
        var commentURL = '/api/comments/' + commentJSON.id;
        var upvotesURL = commentURL + '/upvotes/';

        if(commentJSON.userHasUpvoted) {
            $.ajax({
                type: 'post',
                url: upvotesURL,
                data: {
                    comment: commentJSON.id
                },
                success: function() {
                    success(commentJSON)
                },
                error: error
            });
        } else {
            $.ajax({
                type: 'delete',
                url: upvotesURL + upvoteId,
                success: function() {
                    success(commentJSON)
                },
                error: error
            });
        }
    }
});
uploadAttachments

A callback function that is used to upload attachments to the server. The first parameter of the callback is commentArray including all the attachments as comment models where file field contains the file to be uploaded. The server should return the url for the uploaded file in fileURL field. The callback provides both success and error callbacks which should be called based on the result from the server. The success callback takes an array of successfull uploads as a parameter.

function(commentArray, success, error) {
    success(commentArray);
}
$('#comments-container').comments({
    uploadAttachments: function(commentArray, success, error) {
        var responses = 0;
        var successfulUploads = [];

        var serverResponded = function() {
            responses++;

            // Check if all requests have finished
            if(responses == commentArray.length) {
                
                // Case: all failed
                if(successfulUploads.length == 0) {
                    error();

                // Case: some succeeded
                } else {
                    success(successfulUploads)
                }
            }
        }

        $(commentArray).each(function(index, commentJSON) {

            // Create form data
            var formData = new FormData();
            $(Object.keys(commentJSON)).each(function(index, key) {
                var value = commentJSON[key];
                if(value) formData.append(key, value);
            });

            $.ajax({
                url: '/api/comments/',
                type: 'POST',
                data: formData,
                cache: false,
                contentType: false,
                processData: false,
                success: function(commentJSON) {
                    successfulUploads.push(commentJSON);
                    serverResponded();
                },
                error: function(data) {
                    serverResponded();
                },
            });
        });
    }
});
hashtagClicked

A callback function that is called after user has clicked a hashtag

function(hashtag) {}
$('#comments-container').comments({
    hashtagClicked: function(hashtag) {
        location.hash = 'tags/' + hashtag
    }
});
pingClicked

A callback function that is called after user has clicked a ping

function(ping) {}
$('#comments-container').comments({
    pingClicked: function(ping) {
        location.hash = 'users/' + ping
    }
});
Formatters
textFormatter

A callback function that is called for strings before inserting to DOM. Can be used for localization for instance.

function(text) {
    return text;
}
$('#comments-container').comments({
    textFormatter: function(text) {
        return i18n.translate(text);
    }
});
timeFormatter

A callback function that is called for timestamps before inserting to DOM. Can be used for relative times for instance.

function(time) {
    return new Date(time).toLocaleDateString();
}
$('#comments-container').comments({
    timeFormatter: function(time) {
        return moment(time).fromNow();
    }
});
Miscellaneous
defaultNavigationSortKey

A string value determing the default sorting. Possible values are newest, oldest, popularity and attachments

"newest"
$('#comments-container').comments({
    defaultNavigationSortKey: 'popularity'
});
roundProfilePictures

A boolean value determing whether profile pictures are rounded

false
$('#comments-container').comments({
    roundProfilePictures: true
});
textareaRows

An integer value determing how many rows there are in the commenting fields

2
$('#comments-container').comments({
    textareaRows: 1
});
textareaRowsOnFocus

An integer value determing how many rows there are in the commenting fields on focus

2
$('#comments-container').comments({
    textareaRowsOnFocus: 4
});
textareaMaxRows

An integer or a boolean value determing the maximum amount of rows in commenting fields as they increase when typing. If set to false, commenting fields will increase infinitely.

5
$('#comments-container').comments({
    textareaMaxRows: false
});
maxRepliesVisible

An integer value determing the maximum amount of replies that are visibile intially under a comment. The hidden replies can be shown by clicking the button with a text set in viewAllRepliesText option.

2
$('#comments-container').comments({
    maxRepliesVisible: 3
});

Backend/API implementation

This project doesn't take any stance on how you implement your backend and APIs for providing the library with the information it needs. However, as there have been many requests for it, you can find the documentation of the comment related endpoints for our REST API below as a reference.

Comments REST API documentation

Dependencies

Maintainers

Browser support

IE9+ and all modern browsers

Copyright and license

Code and documentation copyright 2017 Viima Solutions Oy. Code released under the MIT license.