A Blog Not Limited

to web design, standards & semantics

Live Comment Preview for ExpressionEngine

Jul 19, 2008

Published in

Much of the functionality and organization I'm implementing on this blog has been inspired by Jason Santa Maria. On his newly-redesigned blog, he provides a live comment preview that I just love. So, that's what I decided I wanted for A Blog Not Limited.

Unfortunately, the built-in comment preview functionality for ExpressionEngine doesn't even come close.

Quick & Dirty

In a previous article, I mentioned the LivePreview script I discovered on the EE Wiki.

However, as I also mentioned, this script lacked several key features I wanted:

  • Unobtrusive
  • Comment author's name to preview as a link if they provide a URL entry
  • Comment preview to display links if the user provides them in the comment

Enter jQuery

I did a little poking around on the internet and found Karl Swedberg's Really Simple Live Comment Preview, which uses jQuery.

This is an excellent little script and explanation of its implementation.

My Implementation

As a designer with very little understanding of JavaScript, I always appreciate it when a fellow web professional is extremely detailed with explanations.

So, in hopes of helping other similarly-challenged folks out there, the following are the steps I took to 1) get jQuery in place and 2) implement Karl's solution.

You can also skip my lengthy explanation and go directly to the final code.

Loading jQuery

My extremely patient and helpful friend Ian recommended that I use Google's AJAX Libraries API for jQuery (rather than downloading jQuery to my server and referencing it from there).

Apparently, this approach is beneficial for caching purposes. And all it required was the addition of the following to my head:

  1. <script type="text/javascript" src="http://www.google.com/jsapi"></script>
  2. <script type="text/javascript">google.load("jquery", "1.2.6");</script>
Form Markup

Next, I made a few modifications to the default EE comment form markup for accessibility:

  • Added fieldset
  • Nested the form fields in label tags, rather than p
  • Assigned id values to the inputs.
  • Added tabindex values to the inputs

Here is the form markup, contained by the required EE comment form tag:

  1. {exp:comment:form weblog="articles"}
  2. <fieldset>
  3.       <label for="name">Name: <input type="text" name="name" value="{name}" size="50" id="name" tabindex="1" /></label>
  4.       <label for="email">Email:<input type="text" name="email" id="email" value="{email}" size="50" tabindex="2" /></label>
  5.       <label for="url">URL: <input type="text" name="url" id="url" value="{url}" size="50" tabindex="3" /></label>
  6.       <label for="comment">Comment:<textarea name="comment" cols="38" rows="10" id="comment" tabindex="4">{comment}</textarea></label>
  7.       <input type="submit" name="submit" value="Submit" tabindex="5" />
  8. </fieldset>
  9. {/exp:comment:form}
One More jQuery Consideration

For most events, jQuery requires the $(document).ready() function in the head, following the aforementioned jQuery loading scripts.

And due to how I am currently serving my pages, I added the CDATA tag so my markup would validate.

  1. <script type="text/javascript">
  2.       // <![CDATA[
  3.             $(document).ready();
  4.       // ]]>
  5. </script>

I then added Karl's function to $(document).ready(). I won't even begin to attempt to detail Karl's function. Just reference his excellent documentation for a full and easy–to–understand explanation.

However, as useful as Karl's solution was, it didn't quite give me everything that I wanted. So, I began hacking away to get closer to my desired live comment preview.

Let the Hacks Begin

I wanted to make the following changes to Karl's function to get it closer to my vision:

  • Comment preview markup after the form, not within it
  • Suppress preview of markup (b, i, u, img) that I've chosen not to allow in my comments
  • Preview commenter's name, in addition to comment text
  • If the user enters a URL, have the commenter's name preview as a link to that URL
  • Unobtrusive
Preview Markup & Location

I created the markup for my comment preview based on what I envisioned and added it to the page after the form markup:

  1. <div id="preview">
  2.       <h3>What It Will Look Like:</h3>
  3.       <p>Commenter says:<p>
  4.       <p class="liveCommentPreview"></p>
  5. <div>

I then modified Karl's function. His $(this).parent().after() traversal specified that when focus was on the "Comment" textarea, the specified preview markup would be inserted after this element's parent.

I changed this to a $(this).replaceWith() manipulation, so that my live preview would replace the markup I had added after the form:

  1. $('#comment').one('focus',function() {
  2.       $('#liveCommentPreview').replaceWith('<p id="live-comment-preview"></p>');
  3. });
Fun With Regular Expressions

In order to get the the preview to suppress formatting of markup my comment form won't accept, I added an extremely hacked together regular expression:

  1. $comment = $comment.replace("<i>", "").replace("</i>","").replace("<b>", "").replace("</b>","").replace("<u>", "").replace("</u>","").replace("<img", "img");
Commenter's Name

To display the commenter's name, I added a span to my comment preview markup:

  1. <p><span id="liveNamePreview">Commenter</span> says:</p>

I also had to modify the id value for my "Name" input. Apparently "name" is global property in JavaScript and using it as a variable should be avoided. So, I changed it:

  1. <label for="myName">Name: <input type="text" name="name" value="{name}" size="50" id="myName" tabindex="1" /></label>

Note: Under normal circumstances, I always keep the id value identical to the name value in my forms. However, given the aforementioned issue with JavaScript and the default (and required) EE name value, the id and name values are different for this input.

Next I added the JavaScript, using Karl's original code as my foundation:

  1. $('#myName').one('blur',function() {
  2.       $('#liveNamePreview').replaceWith('<span id="live-name-preview"></span>');
  3. });
  4. var $myName = ''; // two single quotes
  5. $('#myName').blur(function() {
  6.       $myName = $(this).val();
  7.       $('#live-name-preview').html( $myName );
  8. });

This script specifies that when the "Name" input loses focus (blur), the specified markup (span id="live-name-preview") will replace the span id="liveNamePreview" I added to my comment preview markup.

The content entered in the input will then be written inside the generated span id="live-name-preview".

Now to get the commenter name to appear as a link if a URL is entered … First, I created another script:

  1. var $url = ''; // two single quotes
  2. $('#url').one('blur',function() {
  3.       $('#live-name-preview').replaceWith('<a id="live-url-preview" href=""></a>')
  4.       $url = $(this).val();
  5.       $('#live-url-preview').attr({href : $url});
  6.       $('#live-url-preview').html( $myName );
  7. });

This script specifies that when the "URL" input loses focus (blur), a id="live-url-preview" will replace the generated span id="live-name-preview".

Then, the URL entered in the input will then be written as the href value for the generated a id="live-url-preview".

Make It Unobtrusive

Lastly, I wanted this script to be unobtrusive, so I removed the comment preview markup from my XHTML and added the following to my script before the live preview functions:

  1. $('#commentForm').after('<div id="preview"><h3>What It Will Look Like:</h3><p><span id="liveNamePreview">Commenter</span> says:</p><p id="liveCommentPreview"></p></div>');

So, if JavaScript is enabled, this script writes the comment preview markup to the page after the form. If JavaScript is disabled, no comment preview markup is generated and, therefore, the live preview functionality isn't triggered.

The Final Product

I have absolutely no doubt there are more efficient, clean and secure ways of approaching a live comment preview. But this is what I — as a humble designer with little JS knowledge — came up with.

I fully expect to make changes to this script as I continue with the development on this blog, and as I test across browsers. But, for now, I'm pretty satisfied.

JavaScript

If you care to reference this experiment in full, here's the final JavaScript:

  1. <script type="text/javascript" src="http://www.google.com/jsapi"></script>
  2. <script type="text/javascript">google.load("jquery", "1.2.6");</script>
  3. <script type="text/javascript">
  4.       // <![CDATA[
  5.       $(document).ready(function(){
  6.             $('#commentForm').after('<div id="preview"><h3>What It Will Look Like:</h3><p><span id="liveNamePreview">Commenter</span> says:</p><p id="liveCommentPreview"></p></div>');
  7.             $('#myName').one('blur',function() {
  8.                   $('#liveNamePreview').replaceWith('<span id="live-name-preview"></span>');
  9.             });
  10.             var $myName = ''; // two single quotes
  11.             $('#myName').blur(function() {
  12.                   $myName = $(this).val();
  13.                   $('#live-name-preview').html( $myName );
  14.             });
  15.             var $url = ''; // two single quotes
  16.             $('#url').one('blur',function() {
  17.                   $('#live-name-preview').replaceWith('<a id="live-url-preview" href=""></a>')
  18.                   $url = $(this).val();
  19.                   $('#live-url-preview').attr({href : $url});
  20.                   $('#live-url-preview').html( $myName );
  21.             });
  22.             $('#comment').one('focus',function() {
  23.                   $('#liveCommentPreview').replaceWith('<p id="live-comment-preview"></p>');
  24.             });
  25.             var $comment = ''; // two single quotes
  26.             $('#comment').keyup(function() {
  27.                   $comment = $(this).val();
  28.                   $comment = $comment.replace(/\n/g, "<br />").replace(/\n\n+/g, '<br /><br />').replace(/(<\/?)script/g,"$1noscript");
  29.                   $comment = $comment.replace("<i>", "").replace("</i>","").replace("<b>", "").replace("</b>","").replace("<u>", "").replace("</u>","").replace("<img", "img");
  30.                   $('#live-comment-preview').html( $comment );
  31.             });
  32.       });
  33.       // ]]>
  34. </script>
Markup

And here is the final form markup:

  1. {exp:comment:form weblog="articles"}
  2. <fieldset>
  3.       <label for="myName">Name: <input type="text" name="name" value="{name}" size="50" id="myName" tabindex="1" /></label>
  4.       <label for="email">Email:<input type="text" name="email" id="email" value="{email}" size="50" tabindex="2" /></label>
  5.       <label for="url">URL: <input type="text" name="url" id="url" value="{url}" size="50" tabindex="3" /></label>
  6.       <label for="comment">Comment:<textarea name="comment" cols="38" rows="10" id="comment" tabindex="4">{comment}</textarea></label>
  7.       <input type="submit" name="submit" value="Submit" tabindex="5" />
  8. </fieldset>
  9. {/exp:comment:form}
HTML5 Cookbook

Interested in HTML5?
Get the Cookbook!

I was a contributing author for HTML5 Cookbook, available for sale on Amazon! Get yours now! (I hear chapters 1, 4 and 5 are particularly good.)

P.S. Don't forget my book Microformats Made Simple is still for sale!

Tags:

Share the Love

Ian Pitts's Gravatar

Ian Pitts opines:

07/20/2008

Great post. I’ll have to try it out when I finally get around to cleaning up my blog and doing things the right way.

One thing I noticed though… while writing this comment, I’m not seeing the live preview. (Even tried in Safari and FF3)

You can reduce the “illegal markup cleansing” regular expression string to this: (</?(b|i|img|u)>)

Emily's Gravatar

Emily responds:

07/20/2008

@Ian Thanks for the suggestion about the regular expression. I’ll give that a shot.

Not sure why the live preview isn’t working for you ... Works for me in all my browsers (FF3, Opera, Safari, Camino, IE6, IE7).

I’ll have to look into it further to figure out what the issue might be that is causing problems for you.

Question: I see the link you tried to setup in your comment to your blog didn’t show up. Did you enter an href and it got stripped out or did you inadvertently forget to add it?

Emily's Gravatar

Emily responds:

07/20/2008

@Ian Nevermind, I completely forgot that the problem I see with your (and my) submitted links is a known bug with ExpressionEngine:

http://expressionengine.com/forums/viewthread/84725/

OrganizedFellow's Gravatar

OrganizedFellow opines:

08/25/2008

Enjoying your site very much. It’s an amazing feeling to get the AHA! moment of EE usefullness, isn’t it? :)

Emily's Gravatar

Emily responds:

08/26/2008

@OrganizedFellow - Thanks! Glad to know that even though this blog is still being developed, it is serving some purpose beyond my own ;-)

Completely know what you mean about the AHA moment, though I’m not entirely sure I’m there yet. Close ... but I still regularly find myself struggling as I add new features. Trackbacks, for example, have held me up the past few days.

Dimox's Gravatar

Dimox opines:

11/22/2008

Thanks for amazing script!

I have one issue. After I specify my name and site URL, if I change them, there is no changes in live preview.

(sorry for my English)

OrganizedFellow's Gravatar

OrganizedFellow opines:

11/22/2008

I am making this comment from the recently released T-Mobile G1 Android phone. Live Comment Preview works AS EXPECTED, 100%!

:)

Björn Dietzel's Gravatar

Björn Dietzel opines:

07/21/2010

Hi Emily you need to clean your comments - a lot of spam here.

I have a question. EE uses BBcode for the comments. If i put “<” in here it normaly does not work in the comment. But “[” does not work in the preview. So how do you do that?

Ok i make a little test now. BBcode A HTML   A

Björn Dietzel's Gravatar

Björn Dietzel opines:

07/21/2010

Ok, me again after the test. HTML works in your comments. On my EE2 it does not…

Ana Luiza's Gravatar

Ana Luiza opines:

10/20/2010

The built-in comment preview in EE is a joke! Anyone who gets over 10 comments a day will miss comments, unless they check every hour. I had to pay my developer a good chunk of money to make a comment preview module like the one built into WordPress.

Commenting is not available in this channel entry.

The Coolest Person I Know

Emily Lewis

Yeah, that would be me: .

I'm a freelance web designer of the standardista variety, which means I get excited about things like valid POSH, microformats and accessibility. I ply my trade from my one-person design studio in Albuquerque, New Mexico 87106 USA.

A Blog Not Limited is my personal blog where I pontificate about web design, web standards, semantics and whatever else strikes my fancy. Head on over to Emily Lewis Design if you'd like to see my work or, even better, hire me.

More

I Tweet, Therefore I Am

Follow @emilylewis on Twitter!