Setup Comments extended with jQuery in CGBlog Module

When working on this blog, i needed comments function as every other blog in the virtual world.

As we already know, CMSMS and Modules work a bit diferently than in other CMS Systems we know, but in a positive way. If we install a module in CMSMS we do not get a bloat of a code and other functions that we possibly do not need.
To make it short, each module can be extended with additional functions by installing other compatible modules.

By installing CGBlog module we only get Bloging function and nothing else, so if we want to include Comments in our Blog we have to install another module called CGFeedback, which again can be used anywhere and not only in CGBlog, for example for Products ratings, simple Content pages commenting or whatever you can think of. 

So how was this done here?

First we need to install CGFeedback module under "Extensions -> Module Manager".
When installation is done we move to CGBlog under "Content -> CGBlog", click on tab "Detail Templates" and open the Template we are using for CGBlog detail posts. Default Template looks something like this.

{if isset($entry->canonical)}
    {assign var='canonical' value=$entry->canonical}
{/if}

{if $entry->postdate}
    <div id="CGBlogPostDetailDate">
        {$entry->postdate|cms_date_format}
    </div>
{/if}

<h3 id="CGBlogPostDetailTitle">{$entry->title|escape}</h3>
<hr id="CGBlogPostDetailHorizRule" />
{if $entry->summary}
    <div id="CGBlogPostDetailSummary">
        <strong>{eval var=$entry->summary}</strong>
    </div>
{/if}
{if $entry->categories}
    <div class="CGBlogSummaryCategory">
        {strip}{$category_label} {foreach from=$entry->categories item='category'} {$category.name} {/foreach}{/strip}
    </div>
{/if}
{if $entry->author}
    <div id="CGBlogPostDetailAuthor">
        {$author_label} {$entry->author}
    </div>
{/if}

<div id="CGBlogPostDetailContent">
    {eval var=$entry->content}
</div>

{if $entry->extra}
    <div id="CGBlogPostDetailExtra">
        {$extra_label} {$entry->extra}
    </div>
{/if}
{if isset($entry->fields)}
    {foreach from=$entry->fields item='field'}
        <div class="CGBlogDetailField">
            {if $field->type == 'file'}
                <img src="{$entry->file_location}/{$field->value}"/>
            {else}
                {$field->name}: {eval var=$field->value}
            {/if}
        </div>
    {/foreach}
{/if}

Now we add the Comments function at the bottom of Template.

{if isset($entry->canonical)}
    {assign var='canonical' value=$entry->canonical}
{/if}
{if $entry->postdate}
    <div id="CGBlogPostDetailDate">
        {$entry->postdate|cms_date_format}
    </div>
{/if}

<h3 id="CGBlogPostDetailTitle">{$entry->title|escape}</h3>
<hr id="CGBlogPostDetailHorizRule" />

{if $entry->summary}
    <div id="CGBlogPostDetailSummary">
        <strong>{eval var=$entry->summary}</strong>
    </div>
{/if}
{if $entry->categories}
    <div class="CGBlogSummaryCategory">
        {strip}{$category_label} {foreach from=$entry->categories item='category'}{$category.name} {/foreach}{/strip}
    </div>
{/if}
{if $entry->author}
    <div id="CGBlogPostDetailAuthor">
        {$author_label} {$entry->author}
    </div>
{/if}
    <div id="CGBlogPostDetailContent">
        {eval var=$entry->content}
    </div>
{if $entry->extra}
    <div id="CGBlogPostDetailExtra">
        {$extra_label} {$entry->extra}
    </div>
{/if}
{if isset($entry->fields)}
    {foreach from=$entry->fields item='field'}
        <div class="CGBlogDetailField">
            {if $field->type == 'file'}
                <img src="{$entry->file_location}/{$field->value}"/>
            {else}
                {$field->name}: {eval var=$field->value}
            {/if}
        </div>
    {/foreach}
{/if}

<h3>Comments</h3>
{if $num_comments != '0'}
    {CGFeedback key1="CGBlog" key2=$entry->id action="summary"}
{else}
<p>
    There are no comments on this article. Be the first to post a comment!
</p>
{/if}

<h3>Leave a Comment</h3>

{CGFeedback key1="CGBlog" key2=$entry->id action="default"}

And here you go, now we have a summary of Comments below our post, if there are no comments a message is displayed and we have a Form for comment submission.

My problem with CGFeedback was that after submiting the comment you were taken to confirmation page and this is where jQuery comes in (i also have to say big thanks to Peciura for helping me with this problem).

First we need to edit our CGFeedback Form Template, you can find it under "Content -> Calguys Feddback Module" and click on "Comment Forms Template" tab. This is the default Form template.

{* comment form template *}
{if isset($message)}
    <div class="pagemessage">
        {$message}
    </div>
{else}
{* no message... display the form *}
    <div class="cgfeedback_addcoment">
        {if isset($error)}
        <div class="error">
            {$error}
        </div>
        {/if}

{$formstart}
    <fieldset style="margin: 1em;">
        <legend>
             {$mod->Lang('prompt_add_comment')} 
        </legend>
        <div class="row" style="margin: 1em;">
            <div class="col30" style="float: left; width: 29%;">
                {$mod->Lang('prompt_title')}:
            </div>
            <div class="col70" style="float: left; width: 70%;">
                <input type="text" name="{$actionid}title" size="80" maxlength="255" value="{$title}"/>
            </div>
        </div>
        <div class="clearfix"></div>
        <div class="row" style="margin: 1em;">
            <div class="col30" style="float: left; width: 29%;">
                {$mod->Lang('prompt_your_name')}:
            </div>
            <div class="col70" style="float: left; width: 70%;">
                <input type="text" name="{$actionid}author_name" size="40" maxlength="255" value="{$author_name}"/>
            </div>
        </div>
        <div class="clearfix"></div>
        <div class="row" style="margin: 1em;">
            <div class="col30" style="float: left; width: 29%;">
                {$mod->Lang('prompt_your_email')}:
            </div>
            <div class="col70" style="float: left; width: 70%;">
                <input type="text" name="{$actionid}author_email" size="40" maxlength="255" value="{$author_email}"/>
            </div>
        </div>
        <div class="clearfix"></div>
        <div class="row" style="margin: 1em;">
            <div class="col30" style="float: left; width: 29%;">
                {$mod->Lang('prompt_notify')}:
            </div>
            <div class="col70" style="float: left; width: 70%;">
                <input type="checkbox" name="{$actionid}author_notify" value="1" {if $author_notify == 1}checked="checked"{/if}/>
            </div>
        </div>
        <div class="clearfix"></div>
        <div class="row" style="margin: 1em;">
            <div class="col30" style="float: left; width: 29%;">
                {$mod->Lang('prompt_your_rating')}:
            </div>
            <div class="col70" style="float: left; width: 70%;">
                <select name="{$actionid}rating">
                    {html_options options=$rating_options selected=$rating}
                </select>
            </div>
        </div>
        <div class="clearfix"></div>
        <div class="row" style="margin: 1em;">
            <div class="col30" style="float: left; width: 29%;">
                {$mod->Lang('prompt_comment')}:
            </div>
            <div class="col70" style="float: left; width: 70%;">
                {$input_comment}
            </div>
        </div>
        <div class="clearfix"></div>
        {* custom fields *}
        {if isset($fields)}
            {foreach from=$fields key='fieldid' item='field'}
            <div class="row" style="margin: 1em;">
                <div class="col30" style="float: left; width: 29%;">
                    {$field.name}:
                </div>
                <div class="col70" style="float: left; width: 70%;">
                    {if isset($field.input)}
                        {$field.input}
                    {elseif $field.type == 0 or $field.type == 1 }
                        <input type="text" name="{$actionid}field_{$fieldid}" value="{$field.value}" size="{$field.attrib.length}" maxlength="{$field.atrrib.maxlength}"/>
                    {elseif $field.type == 2}
                        {* text area fields should have an input... so this should never get caled... but just in case *}
                        <textarea name="{$actionid}field_{$fieldid}">{$field.value}</textarea>
                    {elseif $field.type == 3}
                        <select name="{$actionid}field_{$fieldid}">
                            {html_options options=$field.attrib.options selected="{$field.value}"}
                        </select>
                    {elseif $field.type == 4}
                        <select multiple="multiple" size="4" name="{$actionid}field_{$fieldid}[]">
                            {html_options options=$field.attrib.options selected="{$field.value}"}
                        </select>
                    {/if}
                </div>
            </div>
            {/foreach}
        {/if}
        {if isset($captcha_img)}
        {* handle captcha image *}
            <div class="row" style="margin: 1em;">
                <div class="col30" style="float: left; width: 29%;">
                     
                </div>
                <div class="col70" style="float: left; width: 70%;">
                    {$captcha_img}
                    <br/>
                    <input type="text" name="{$actionid}feedback_captcha" value="" size="20"/>
                </div>
            </div>
        {/if}
        <div class="row" style="margin: 1em;">
            <div class="col30" style="float: left; width: 29%;">
                 
            </div>
            <div class="col70" style="float: left; width: 70%;">
                <input type="submit" name="{$actionid}submit" value="{$mod->Lang('submit')}"/>
            </div>
        </div>
        <div class="clearfix"></div>
    </fieldset>
    {$formend}
</div>
{/if}

The first thing i have done is removing all those div's and replaced it with better markup using <label> and preventing divitis.
Next thing was adding an empty div with id cgfeedback_message that will be targeted by jQuery function, form it self is wrapped inside div with class cgfeedback_addcomment.
Another thing i didn't like was that title was needed for each comment, this was replaced by small bit of code like this:

{capture assign='tmp'}
    <input type="hidden" value="{$entry->title}" name="{$actionid}title"/>
</div>
{/capture}

{$formstart|replace:'</div>':$tmp}

Now our Title input field is hidden and gets the title of Blog post as it's value.
See my complete Form template below. 

{if isset($message)}
    <div class="pagemessage" >
        {$message}
    </div>
{elseif  isset($error)}
    <div class="error">
        {$error}
    </div>
{else}
    <div id="cgfeedback_message"></div>
        <div class="cgfeedback_addcoment">
        {capture assign='tmp'}
            <input type="hidden" value="{$entry->title}" name="{$actionid}title"/>
        </div>
        {/capture}
        
{$formstart|replace:'</div>':$tmp}
<fieldset>
    <legend>
        {$mod->Lang('prompt_add_comment')}
    </legend>
    <label>{$mod->Lang('prompt_your_name')}:</label>
        <input type="text" name="{$actionid}author_name" size="40" maxlength="255" value="{$author_name}" />
    {if isset($fields)}
        {foreach from=$fields key='fieldid' item='field'}
            <label>{$field.name}:</label>
            {if isset($field.input)}
                {$field.input}
            {elseif $field.type == 0 or $field.type == 1 }
                <input type="text" name="{$actionid}field_{$fieldid}" value="(Optional)" size="40" maxlength="255" {literal}onfocus="if(this.value==this.defaultValue) this.value='';" onblur="if(this.value=='') this.value=this.defaultValue;"{/literal} />
            {/if}
        {/foreach}
    {/if}
    <label>{$mod->Lang('prompt_your_email')} (will not be displayed):</label>
        <input type="text" name="{$actionid}author_email" size="40" maxlength="255" value="{$author_email}" />
    <label>{$mod->Lang('prompt_notify')}:</label>
        <input class="checkbox" type="checkbox" name="{$actionid}author_notify" value="0" {if $author_notify == 1}checked="checked"{/if} />
    <label>Enter Your Comments:</label>
        {$input_comment}
        <input type="submit" class="submit" name="{$actionid}submit" value="{$mod->Lang('submit')}" />
</fieldset>
{$formend}
</div>
{/if}

The next thing we need to do is add some styling for our div's created in the form as we do not want these to be visible all the time. Open your Stylesheet and the code below.

div#cgfeedback_message {
    display: none; /*we hide this div since it will get displayed with help of jquery*/
    width: 100%; /*add your width*/
}
div#cgfeedback_message div.error/*we add some styling to error message*/ {
    padding: 15px;
    margin-bottom: 10px;
    background: #f93030;
    z-index: 1;
    color: #fff;
    border: 5px solid #f00;
}
div#cgfeedback_message div.pagemessage/*and we add some styling to our success message*/ {
    padding: 15px;
    background: #51d02a;
    z-index: 1;
    border: 5px solid #2fbf03;
}

Now all we need is the jQuery function that will collect the data from form, submit the form and display either error or success message.
Open your Page template and add following code either in the <head> </head> part or as i prefer at the bottom of the page before closing </body> tag. 

<!-- first we need jquery framework -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
<!-- and this is the function -->
jQuery(document).ready(function() {
    jQuery(".cgfeedback_addcoment input[type='submit']").live('click', function(event) {
        event.preventDefault();
        var cgfeedback_form = jQuery(this).closest('form');
        var cgfeedback_form_fields = cgfeedback_form.find(':input').serializeArray()
        var form_data = '';
        jQuery.each(cgfeedback_form_fields, function(i, field) {
            if (cgfeedback_form.find("input[name='" + field.name + "']").not(':checkbox') || cgfeedback_form.find("input[name='" + field.name + "']").is(':checked')) {
                form_data = form_data + field.name + '=' + field.value + '&';
            }
        });
        form_data = form_data + cgfeedback_form.find("input[name$='submit']").attr('name') + '=' + cgfeedback_form.find("input[name$='submit']").val() + '&' + 'showtemplate=false';
        var cgfeedback_url = jQuery(location).attr('href').replace(jQuery(location).attr('hash'), '') + '/?showtemplate=false';
        //alert(form_data);
        //jQuery('#cgfeedback_message').html(form_data).fadeIn('3000');

        jQuery.ajax({
            type : 'POST',
            url : cgfeedback_url,
            data : form_data,
            success : function(data) {
                jQuery('#cgfeedback_message').html(data).fadeIn('3000').delay('3000').fadeOut('3000');
                //jQuery('#comments_inner').parent().load( cgfeedback_url + ' #comments_inner'); //could be used if comments are not moderated
            }
        });
    });
});

jQuery(document).ready(function() {
    jQuery("#cgfeedback_message").live('click', function() {
        jQuery(this).hide();
    });
}); 
</script>

And thats it, we have our Comments setup for each Blog post and comments are not being redirected to success page after submission except the visitor has JavaScript turned off.

Just post a Comment here and you will see how it works. 

a2 Hosting

Comments