Ajax enabled comments for Movabletype explained
Some days ago, I posted about realizing Ajax enabled comments in Movabletype. Here is how.
Why Ajax comments
When you comment a post on a blog, the page that contains the form you have filled and sent reloads. Instead, using Ajax only part of the page is reloaded.
From the client side, Ajax is substantially a Javascript, more or less complex, that simulates a browser without interface inside the browser you are using. The responses to the requests made by this pseudo-browser are interpreted by the script and translated in live changes to the page you are on.
From the server side, Ajax is… nothing! The pseudo-browser makes standard requests and receives standard responses. You only need to request the right page at the right moment.
But…
My first idea for implementing Ajax on MT was hacking the Perl. The second one was writing a plugin. But reading MT’s code I had a surprise!
From the file Comments.pm of MT library:
# Form a link to the comment
my $comment_link;
if (!$q->param('static')) {
my $url = $app->base . $app->uri;
$url .= '?entry_id=' . $q->param('entry_id');
$url .= '&static=0&arch=1' if ($q->param('arch'));
$comment_link = $url;
} else {
my $static = $q->param('static');
if ($static == 1) {
# I think what we really want is the individual archive.
$comment_link = $entry->permalink;
} else {
$comment_link = $static . '#' . $comment->id;
}
}
...
return $app->redirect($comment_link);
That static
parameter, which is almost ignored in Movabletype documentation, is the key of everything: if the request includes a parameter named static
with value different from 1, the value of that parameter is used like an URL to redirect the user.
The trick is all here. A little bit of Javascript makes the rest.
The client side
The Javascript is composed by 2 fundamental functions.
function initializeAjax() { var s = false; if (typeof XMLHttpRequest != 'undefined') { s = new XMLHttpRequest(); } else { try { s = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { s = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) { s = false; } } }
return s; }
initializeAjax()
is the function that returns the hidden browser, which is a software object on which you can operate using a series of functions.
function sendComment(response_page) {
connection = initializeAjax(); if (!connection) { return true; }
var remember = ""; var forget = "";
var fields = document.getElementById("comments_form").elements;
fields["post"].setAttribute("disabled", "true"); fields["post"].setAttribute("value", "Processing...");
var requestText = ''; requestText += "author="+encodeURIComponent(fields["author"].value); requestText += "&entry_id="+encodeURIComponent(fields["entry_id"].value); requestText += "&email="+encodeURIComponent(fields["email"].value); requestText += "&url="+encodeURIComponent(fields["url"].value); requestText += "&text="+encodeURIComponent(fields["text"].value); requestText += "&static="+encodeURIComponent(response_page); requestText += "&post="+encodeURIComponent('POST'); if (fields["remember"] && fields["remember"].checked==true) requestText += "&remember="+encodeURIComponent(fields["remember"].value); if (fields["forget"] && fields["forget"].checked==true) requestText += "&forget="+encodeURIComponent(fields["forget"].value);
connection.open("POST","/cgi-bin/mt/mt-comments.cgi",true); connection.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8'); connection.setRequestHeader('Content-Length', requestText.length);
connection.onreadystatechange = function() { if (connection.readyState == 4) { response = connection.responseText; if ( (connection.status == 200 && response != "invalid") && !response.match(/<html>.*<\/html>/) && !response.match(/<meta[^>]*>/)) { document.getElementById("comments").innerHTML = response; } else { window.alert("Spiacente, ma non e' possibile processare ora il tuo commento. Prova piu' tardi, per favore..."); fields["post"].removeAttribute("disabled"); fields["post"].setAttribute("value", "Post"); } } }
connection.send(requestText);
return false; }
sendComment()
is the function that uses the object returned from initializeAjax()
to send request to the server. Once the request is sent, the function waits for the response, that, if regular, is used used to modify the page. sendComment()
is called when you send the form, using the onsubmit
event of the form
element.
The requestText += "&static="+encodeURIComponent(response_page);
is the trick: when you send the comment, the XMLHttpRequest object – the hidden browser – is redirected to a specific page (the response_page
passed to function sendComment()
).
What page?
The response_page
is a simple page, generated from MT using an individual template. For example, if you have the posts archived by date using <$MTArchiveDate format="%Y/%m/%d"$>/<$MTEntryTitle dirify="1"$>.html
in the Archive File Template, you can create the response_page
using a second individual archive with something like <$MTArchiveDate format="%Y/%m/%d"$>/<$MTEntryTitle dirify="1"$>.ajax.html
. Being of individual type, this template is rebuild every time a comment is posted.
This template generates the content used to substitute the part of the page interested by Ajax: in the case of comments, the
template could generate files containing the HTML code to use with innerHTML
property of a div
element (this is what is done here on sistrall.it).
And if there’s no Javascript?
If Javascript is not available for any reason, everything works just like Ajax doesn’t exists: the form is sent from the real browser, the static
parameter takes the value 1 from an hidden field and MT redirects the user following the standard way.
Conclusions
That’s all: implementing Ajax enabled comments on MT isn’t difficult at all! The technique here explained is one of the simplest, but more can be done generating, for example, response_page
s containing a real XML tree, using the content of different nodes to substitute more elements in the page.
Precedente
13 maggio 2005
Successivo
26 maggio 2005