8 min read
    1. 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  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>

      
      
    2. 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
      }

    3. 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.

Figure 8-7: Screenshot of index.html

  1. Copy palette.png from the code download to your ajax/chat folder.
  2. 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))));
    ?>
  3. 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

element and its inner layers do the trick. The scroll element is the outermost layer; it has a fixed width and height; and its most useful property, overflow, determines how any content that falls (or overflows) outside of its boundaries is displayed. Generally, the content of a block box is confined to the content edges of the box. In CSS, the overflow property has four possible values that specify what should happen when an element overflows its area: visible, hidden, scroll, and auto. (For more details, please see the specification of overflow, at http://www.w3.org/TR/REC-CSS2/visufx.html.)

 

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;
 }

LEAVE A REPLY

Please enter your comment!
Please enter your name here