Usability - Productivity - Business - The web - Singapore & Twins

From Blogsphere to a Static Site (Part 5) - Comment front-end

In Part 4 I described the comment backend. This installment sheds a light on the comment front-end.

Comments can be tricky. One lesson I learned early: When your comment form is standard HTML form, it attracts spam like a light bulb attracts moths. So the requirement were:

  • The original blog entry should not contain any HTML form. It should be loaded on a button click using JavaScript. Nota bene: this isn't hide/show, but actual manipulation of the DOM
  • The dynamic form shall not contain a POST URL, but submission should be in JavaScript - keeps a lot of the scumbags out already
  • Submission should be secured with a Captcha
  • Some formatting should be allowed. I opted for a Markdown editor with preview capabilities

The first component is the placeholder for the existing comments and the button showing the comment form:

<a name="comments"></a>
<div class="well well-raised" style="text-align : center">
  <button class="btn btn-lg btn-info" data-toggle="collapse" data-target="#commentform_{{UNID}}" type="button">
    Add your comment...  <span class="glyphicon glyphicon-comment"></span>
<div id="commentform_{{UNID}}" class="collapse"></div>
<div class="well well-raised">
  <ol id="commentList">
      {{#gravatarURL}}<img src="{{.}}" class="gravatarimg" /> {{/gravatarURL}} posted by <b>{{author}}</b> on <i>{{createdString}}</i>:
      <br /> {{& comment}}
      <hr style="clear : both" />
    </li> {{/comments}} {{^comments}}
    <li id="nocomments">
      <h5>No comments yet, be the first to comment</h5>

The second component is the comment form, implemented as mustache template - one of the reasons I picked Mustache: runs on the server and the client in tons of languages

<form title="Comment form for blog discussion" onSubmit="return addComment(this,'{{recaptchaid}}','{{parentId}}')" class="form-vertical well well-raised">
    <legend>Add your comment</legend>
    <p>Please note: <b>Comments without a valid and working eMail address will be removed.</b>
      <br /> This is my site, so I decide what stays here and what goes.</p>
     <div class="control-group" id="commentcontrol">
      <label class="control-label" for="Commentor">Name (required, published)</label>
      <div class="controls">
        <input class="input-xlarge focused" id="Commentor" size="30" accesskey="n" name="nameAuthor" />
      <label class="control-label" for="Email">eMail (required, not published)</label>
      <div class="controls">
        <input type="eMail" class="input-xlarge focused" id="Email" size="30" accesskey="n" name="txtEmail" placeholder="A working eMail please!" />
      <label class="control-label" for="webSite">URL (optional)</label>
      <div class="controls">
        <input type="url" class="input-xlarge" id="webSite" size="30" accesskey="n" name="txtWebSite" />
      <div class="controls">
        <div id="wmd-panel" class="wmd-panel">
          <table style="width : 100%" border="0">
              <td style="width : 50%; vertical-align : top">
                <label class="control-label" for="wmd-input">Your Comment (Use markdown like <a href="//stackoverflow.com/editing-help" target="_blank">Stackoverflow</a>)</label>
                <div id="wmd-button-bar"></div>
                <textarea class="wmd-input" id="wmd-input" name="Body"></textarea>
              <td style="width : 50%; vertical-align : top">
                <label class="control-label">Preview</label>
                <div id="wmd-preview" class="wmd-panel wmd-preview"></div>
      <div class="controls" id="captchadiv">Captcha here</div>
      <div class="form-actions">
        <button id="commentsubmit" type="submit" class="btn btn-primary btn-large">Post your comment</button>
    <div class="alert alert-block" id="alertContainer" style="display : none">One moment please, submitting comment...</div>

The whole mechanism gets to work with just a few jQuery JavaScript functions (Vanilla JS would work too, but I had JQuery already for the social buttons, so I reused that) and the respective JS files:

  • mustache.js
  • blogcomments.js
  • Markdown.Converter.js
  • Markdown.Sanitizer.js
  • Markdown.Editor.j
  • //www.google.com/recaptcha/api/js/recaptcha_ajax.js


var destinationURL = "/blog/comments";

function getCommentForm(recaptchaid, parentId) {
var params = {};
params.recaptchaid = recaptchaid;
params.parentId = parentId;
var result = {};
url: '/blog/js2/comment.mustache',
dataType: 'text',
success: function(template) {
result = Mustache.render(template, params);
async: false
return result;

function addComment(form, recaptchaid, parentId) {
$("#alertContainer").html("One moment please, submitting comment...")

url: destinationURL,
data: {
Commentor: this.Commentor.value,
eMail: this.Email.value,
webSite: this.webSite.value,
Body: this["wmd-input"].value,
rChallenge: this.recaptcha_challenge_field.value,
rResponse: this.recaptcha_response_field.value,
parentId: parentId
success: function(result) {
2000).hide(200, function() {
resetComment(recaptchaid, parentId);
error: function(err) {
.delay(1000).hide(200, function() {
resetComment(recaptchaid, parentId);
return false;

function resetComment(recaptchaid, parentId) {
var hasSuccess = $("div.commentsuccess");
if (hasSuccess.length == 0) {
// It didn't work!
} else {
renderComment(recaptchaid, parentId);

function renderComment(recaptchaid, parentId) {
var fid = "#commentform\_" + parentId;
var form = getCommentForm(recaptchaid, parentId);
if (Recaptcha) {
var theDiv = document.getElementById("captchadiv");
Recaptcha.create(recaptchaid, theDiv, {
tabindex: 1,
theme: "clean"
_, callback : Recaptcha.focus_response_field

// Markdown
var converter1 = Markdown.getSanitizingConverter();
var editor1 = new Markdown.Editor(converter1);

// Comments that are not yet static
url: destinationURL + "?parentid=" + parentId,
type: 'GET',
async: true,
success: function(data) {
if (data && data.length > 0) {
error: function(data) {
// Crude error handling

postJSON: function(params) {
return jQuery.ajax(jQuery.extend(params, {
type: "POST",
data: JSON.stringify(params.data),
dataType: "json",
contentType: "application/json",
processData: false

As usual: YMMV

Posted by on 20 July 2017 | Comments (1) | categories: Blog


  1. posted by flyingtogether on Sunday 24 March 2024 AD: