This is the second part of the article series on AJAX Chat. In this article by Bogdan Brinzarea and Cristian Darie, we will continue to discuss about AJAX Chat implementation in detail. Read AJAX Chat: Part 1 here.
- Create a new file named index.html, and add this code to it:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>AJAX Chat</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="chat.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="jQuery-1.3.2.js" ></script>
<script type="text/javascript" src="chat.js" ></script>
</head>
<body>
<noscript>
Your browser does not support JavaScript!!
</noscript>
<table id="content">
<tr>
<td>
<div id="scroll">
</div>
</td>
<td id="colorpicker">
<img src="palette.png" id="palette" alt="Color Palette" border="1"/>
<br />
<input id="color" type="hidden" readonly="true" value="#000000" />
<span id="sampleText">
(text will look like this)
</span>
</td>
</tr>
</table>
<div>
<input type="text" id="userName" maxlength="10" size="10"/>
<input type="text" id="messageBox" maxlength="2000" size="50" />
<input type="button" value="Send" id="send" />
<input type="button" value="Delete All" id="delete" />
</div>
</body>
</html> - Let's deal with appearances now, creating chat.css and adding the following code to it:
body
{
font-family: Tahoma, Helvetica, sans-serif;
margin: 1px;
font-size: 12px;
text-align: left
}
#content
{
border: DarkGreen 1px solid;
margin-bottom: 10px
}
input
{
border: #999 1px solid;
font-size: 10px
}
#scroll
{
position: relative;
width: 340px;
height: 270px;
overflow: auto
}
.item
{
margin-bottom: 6px
}
#colorpicker
{
text-align:center
} - It's time for another test. We still don't have the color picker in place, but other than that, we have the whole client-server chat mechanism in place. Load index.html at http://localhost/ajax/chat/index.html from multiple browsers and/or computers, and ensure everything works as planned.
- Copy palette.png from the code download to your ajax/chat folder.
- Create a file named color.php and add the following code to it. This is actually the only step left to make the color picker work as expected.
<?php
// the name of the image file
$imgfile='palette.png';
// load the image file
$img=imagecreatefrompng($imgfile);
// obtain the coordinates of the point clicked by the user
$offsetx=$_GET['offsetx'];
$offsety=$_GET['offsety'];
// get the clicked color
$rgb = ImageColorAt($img, $offsetx, $offsety);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// return the color code
echo json_encode(array("color" => sprintf('#%02s%02s%02s', dechex($r), dechex($g), dechex($b))));
?> - Make another test to ensure the color picker works and that your users can finally chat in color.

What just happened?
First, make sure the application works well. Load http://localhost/ajax/chat/index.html with a web browser, and you should get a page that looks like the one in Figure 8-1.
If you analyze the code for a bit, the details will become clear. Everything starts with index.html. The only part that is really interesting in index.html is a scrolling region implemented in DHTML. (A little piece of information regarding scrolling can be found at http://www.dyn-web.com/code/scroll/.)
The scrolling area allows our users to scroll up and down the history of the chat and ensures that any new messages that might flow out of the area are still viewed. In our example, the scroll
As you can see, the HTML file is very clean. It contains only the declarations of the HTML elements that make up the user interface. There are no event handlers and there is no JavaScript code inside the HTML file—we have a clean separation between the user interface and the programming.
In our client-side JavaScript code, in the chat.js file, the action starts with the ready event, which is defined in jQuery (reference: http://docs.jQuery.com/Events/ready) as a replacement for window.onload. In other words, your ready() function, which you can see in the following code snippet, is called automatically after the HTML page has been loaded by the browser, and the page elements can be safely used and manipulated by your JavaScript code:
$(document).ready(function() {
}
Inside this function, we do several operations involving events related to the user interface. Let's analyze each step!
We want to be sure that a username always appears, that is, it should never be left empty. To do this, we can create a function that checks for this and bind it to the blur event of the textbox.
// function that ensures that the username is never empty and //if so a random name is generated
$('#userName').blur(
function(e) {
// ensures our user has a default random name when the form loads
if (this.value == "")
this.value = "Guest" + Math.floor(Math.random() * 1000);
}
);
If the username is empty, we simply generate a random username suffixing Guest with a randomly generated number.
When the page first loads, no username has been set and we trigger the blur event on userName.
// populate the username field with
// the default value
$('#userName').triggerHandler('blur');
The success() function starts by checking if the JSON response contains an errno field, which would mean that an error has happened on the server side. If an error occurred the displayPHPError() function is called passing in the error in JSON format.
// function that displays a PHP error message
function displayPHPError(error)
{
displayError ("Error number :" + error.errno + "rn" +
"Text :"+ error.text + "rn" +
"Location :" + error.location + "rn" +
"Line :" + error.line + + "rn");
}
The displayPHPError() will retrieve the information from the error and call in turn the displayError() function. The displayError() function shows the error message or a generic alert depending on whether the debugging flag is set or not.
// function that displays an error message
function displayError(message) {
// display error message, with more technical details if debugMode is true
alert("Error accessing the server! " +
(debugMode ? message : ""));
}
Next, in our ready event, we set the default color for the sample text to black:
// set the default color to black
$('#sampleText').css('color', 'black');
Moving on, we hook on to the click event of the Send button. The following code is very simple, as the entire logic behind sending a message is encapsulated in sendMessage():
$('#send').click(
function(e) {
sendMessage();
}
);
Moreover, here we hook on to the click event of the Delete all button in a similar way as the Send button.
$('#delete').click(
function(e) {
deleteMessages();
}
);
For the messageBox textbox, where we input messages, we disable autocomplete and we capture the Enter key and invoke the logic for sending a message:
// set autocomplete off
$('#messageBox').attr('autocomplete', 'off');
// handle the enter key event
$('#messageBox').keydown(
function(e) {
if (e.keyCode == 13) {
sendMessage();
}
}
);
Finally, when the page loads, we want to have the messages that have already been posted and we call retrieveNewMessages() function.
Now that we have seen what happens when the page loads, it's time to analyze the logic behind sending and receiving new messages.
Because everything starts when the page loads and the existing messages are retrieved, we will start with retrieveNewMessages() function. The function simply makes an AJAX request to the server indicating the retrieval of the latest messages.
function retrieveNewMessages() {
$.ajax({
url: chatURL,
type: 'POST',
data: $.param({
mode: 'RetrieveNew',
id: lastMessageID
}),
dataType: 'json',
error: function(xhr, textStatus, errorThrown) {
displayError(textStatus);
},
success: function(data, textStatus) {
if(data.errno != null)
displayPHPError(data);
else
readMessages(data);
// restart sequence
setTimeout("retrieveNewMessages();", updateInterval);
}
});
}
The request contains as parameters the mode indicating the retrieval of new messages and the ID of the last retrieved message:
data: $.param({
mode: 'RetrieveNew',
id: lastMessageID
}),
On success, we simply read the retrieved messages and we schedule a new automatic retrieval after a specific period of time:
success: function(data, textStatus) {
if(data.errno != null)
displayPHPError(data);
else
readMessages(data);
// restart sequence
setTimeout("retrieveNewMessages();", updateInterval);
}
Reading messages is the most complicated function as it involves several steps. It starts by checking whether the database has been cleared of messages and, if so, it empties the list of messages and resets the ID of the last retrieved message.
function readMessages(data, textStatus) {
// retrieve the flag that says if the chat window has been cleared or not
clearChat = data.clear;
// if the flag is set to true, we need to clear the chat window
if (clearChat == 'true') {
// clear chat window and reset the id
$('#scroll')[0].innerHTML = "";
lastMessageID = -1;
}
Before retrieving the new messages, we need to check and see if the received messages have not been already processed. If not, we simply store the ID of the last received message in order to know what messages to ask for during the next requests:
if (data.messages.length > 0)
{
// check to see if the first message
// has been already received and if so
// ignore the rest of the messages
if(lastMessageID > data.messages[0].id)
return;
// the ID of the last received message is stored locally
lastMessageID = data.messages[data.messages.length - 1].id;
}
Sign up for a Packt account to see the rest of this article
Now that you've read a few articles, you might want to consider signing up for a Packt account. It takes a matter of seconds, will give you access to all the articles on PacktPub.com, and once you've signed up you'll be returned here to carry on reading your article.
Furthermore, you'll gain access to nine free ebooks, and be offered a free trial of PacktLib, Packt's online library. Simply enter your details here, or log in to your existing account.




Post new comment