Symbianize Forum

Most of our features and services are available only to members, so we encourage you to login or register a new account. Registration is free, fast and simple. You only need to provide a valid email. Being a member you'll gain access to all member forums and features, post a message to ask question or provide answer, and share or find resources related to mobile phones, tablets, computers, game consoles, and multimedia.

All that and more, so what are you waiting for, click the register button and join us now! Ito ang website na ginawa ng pinoy para sa pinoy!

Making an AJAX Web Chat

Heathcliff_

Novice
Advanced Member
Messages
34
Reaction score
0
Points
26
Wala na po akong Demo nitong ajax chat

eto na lng mejo may nabago lng

http://fixed123.fh10.net/shoutbox/index.php

eto pa. pareho na yan may facebook login

http://fixed123.fh10.net/test/index.php

http://fixed123.fh10.net/




Making an AJAX Web Chat (Part 1) – PHP and MySQL

1209.jpg




HTML

As usual, the first step is to lay down the HTML markup. Our document is structured as HTML5 for convenience, as this allows us to use the new, shorter (and more memorable) doctype, and skip the type attribute on the script tags.

ajax-chat.html

Code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>

<!-- Loading the jScrollPane CSS, along with the styling of the
     chat in chat.css and the rest of the page in page.css -->

<link rel="stylesheet" type="text/css" href="js/jScrollPane/jScrollPane.css" />
<link rel="stylesheet" type="text/css" href="css/page.css" />
<link rel="stylesheet" type="text/css" href="css/chat.css" />

</head>

<body>

<div id="chatContainer">

    <div id="chatTopBar" class="rounded"></div>
    <div id="chatLineHolder"></div>

    <div id="chatUsers" class="rounded"></div>
    <div id="chatBottomBar" class="rounded">
        <div class="tip"></div>

        <form id="loginForm" method="post" action="">
            <input id="name" name="name" class="rounded" maxlength="16" />
            <input id="email" name="email" class="rounded" />
            <input type="submit" class="blueButton" value="Login" />
        </form>

        <form id="submitForm" method="post" action="">
            <input id="chatText" name="chatText" class="rounded" maxlength="255" />
            <input type="submit" class="blueButton" value="Submit" />
        </form>

    </div>

</div>

<!-- Loading jQuery, the mousewheel plugin and jScrollPane, along with our script.js -->

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="js/jScrollPane/jquery.mousewheel.js"></script>
<script src="js/jScrollPane/jScrollPane.min.js"></script>
<script src="js/script.js"></script>
</body>
</html>



To optimize the load time, the stylesheets are included in the head section, and the JavaScript files in the footer, just before the closing body tag.
We are using the jScrollPane plugin to create the scrollable area with the chats entries. This plugin comes with its own stylesheet, which is the first thing we’ve included into the page.
The markup of the chat consists of four main divs – the top bar, the chat container, the user container and the bottom bar. The latter holds the login and submit forms. The submit form is hidden by default and only shown if the user has successfully logged in the chat system.


ajax_web_chat_php_mysql_jQuery.jpg



Lastly we include the JavaScript files. Starting with the jQuery library, we add the mousewheel plugin (used by jScrollPane), the jScrollPane plugin itself and our script.js file.


Database Schema


Before we move on with the PHP part, we first have to take a closer look at how the chat data is organized in the MySQL database.
For the purposes of this script we use two tables. In webchat_users we are storing the chat participants. This table has na id, name, gravatar and a last_activity field. The name field is defined as unique, so that no users have duplicate nick names in the chatroom.



webchat_users_table_structure.jpg



Another useful feature of the unique index fields, is that insert queries will fail and the inserted_rows property of the MySQLi object will be set to zero if we attempt to insert a duplicate row. This finds its place in the Chat PHP class you will see in the next step.
The last_activity column holds a timestamp, which is updated every 15 seconds for every user. It is also defined as an index, so it is faster to delete inactive users (having a last_activity column with a greater value than 15, would mean that the user is no longer viewing the chat window).


webchat_lines_table_structure.jpg



The webchat_lines table holds the individual chat entries. Notice that we are storing the author name and gravatar here as well. This duplication is worthwhile as it frees us from using an expensive join when requesting the latest chats – the most frequently accessed feature of the application.


The definitions of these tables are available in tables.sql in the download archive. You can execute the code in phpMyAdmin to create them. Also, when setting up the chat on your own host, remember to modify ajax.php with your MySQL database login details.



PHP


Now that we have the database in place, lets start discussing the PHP scripts that drive the chat.
The first file we are going to take a closer look at, is ajax.php. It handles the AJAX requests sent from the jQuery front end and outputs JSON formatted data.


ajax.php



Code:
require "classes/DB.class.php";
require "classes/Chat.class.php";
require "classes/ChatBase.class.php";
require "classes/ChatLine.class.php";
require "classes/ChatUser.class.php";

session_name('webchat');
session_start();

if(get_magic_quotes_gpc()){

    // If magic quotes is enabled, strip the extra slashes
    array_walk_recursive($_GET,create_function('&$v,$k','$v = stripslashes($v);'));
    array_walk_recursive($_POST,create_function('&$v,$k','$v = stripslashes($v);'));
}

try{

    // Connecting to the database
    DB::init($dbOptions);

    $response = array();

    // Handling the supported actions:

    switch($_GET['action']){

        case 'login':
            $response = Chat::login($_POST['name'],$_POST['email']);
        break;

        case 'checkLogged':
            $response = Chat::checkLogged();
        break;

        case 'logout':
            $response = Chat::logout();
        break;

        case 'submitChat':
            $response = Chat::submitChat($_POST['chatText']);
        break;

        case 'getUsers':
            $response = Chat::getUsers();
        break;

        case 'getChats':
            $response = Chat::getChats($_GET['lastID']);
        break;

        default:
            throw new Exception('Wrong action');
    }

    echo json_encode($response);
}
catch(Exception $e){
    die(json_encode(array('error' => $e->getMessage())));
}



For convenience, I’ve used a simple switch statement to define the actions, supported by the script. These include chat submission, login/logout functionality, and actions for requesting a list of chats and online users.
All output is in the form of JSON messages (conveniently handled by jQuery), and errors are raised in the form of exceptions. The switch statement routes all requests to the appropriate static method of the Chat class, which we will discuss later in this section.



DB.class.php




Code:
class DB {
	private static $instance;
	private $MySQLi;

	private function __construct(array $dbOptions){

		$this->MySQLi = @ new mysqli(	$dbOptions['db_host'],
										$dbOptions['db_user'],
										$dbOptions['db_pass'],
										$dbOptions['db_name'] );

		if (mysqli_connect_errno()) {
			throw new Exception('Database error.');
		}

		$this->MySQLi->set_charset("utf8");
	}

	public static function init(array $dbOptions){
		if(self::$instance instanceof self){
			return false;
		}

		self::$instance = new self($dbOptions);
	}

	public static function getMySQLiObject(){
		return self::$instance->MySQLi;
	}

	public static function query($q){
		return self::$instance->MySQLi->query($q);
	}

	public static function esc($str){
		return self::$instance->MySQLi->real_escape_string(htmlspecialchars($str));
	}
}



The DB class is our database manager. The constructor is private, which means that no objects can be created from the outside, and the initialization is only possible from the init() static method. It takes an array with MySQL login details, and creates an instance of the class, held in the self::$instance static variable. This way we can be sure that only one connection to the database can exists in the same time.


The rest of the classes take advantage of the static query() method to communicate with the database.




ChatBase.class.php


/* This is the base class, used by both ChatLine and ChatUser */

class ChatBase{

// This constructor is used by all the chat classes:

public function __construct(array $options){

foreach($options as $k=>$v){
if(isset($this->$k)){
$this->$k = $v;
}
}
}
}



This is a simple base class. It’s main purpose is to define the constructor, which takes an array with parameters, and saves only the ones that are defined in the class.




ChatLine.class.php



Code:
/* Chat line is used for the chat entries */

class ChatLine extends ChatBase{

    protected $text = '', $author = '', $gravatar = '';

    public function save(){
        DB::query("
            INSERT INTO webchat_lines (author, gravatar, text)
            VALUES (
                '".DB::esc($this->author)."',
                '".DB::esc($this->gravatar)."',
                '".DB::esc($this->text)."'
        )");

        // Returns the MySQLi object of the DB class

        return DB::getMySQLiObject();
    }
}




Here is the ChatLine class. It extends ChatBase, so you can easily create an object of this class by providing an array with a text, author, and gravatar elements. The gravatar property contains a md5 hash of the person’s email address. This is required so we can fetch the user’s gravatar from gravatar.com.

This class also defines a save method, which the object to our database. As it returns the MySQLi object, contained in the DB class, you can check whether the save was successful by checking the affected_rows property (we will come back to this in the Chat class).



ChatUser.class.php



class ChatUser extends ChatBase{

protected $name = '', $gravatar = '';

public function save(){

DB::query("
INSERT INTO webchat_users (name, gravatar)
VALUES (
'".DB::esc($this->name)."',
'".DB::esc($this->gravatar)."'
)");

return DB::getMySQLiObject();
}

public function update(){
DB::query("
INSERT INTO webchat_users (name, gravatar)
VALUES (
'".DB::esc($this->name)."',
'".DB::esc($this->gravatar)."'
) ON DUPLICATE KEY UPDATE last_activity = NOW()");
}
}


The same is also valid here. We have the name and gravatar properties (notice the protected access modifier – this means that they will be accessible in the ChatBase class, so we can set them in the constructor).


The difference is that we also have an update() method, which updates the last_activity timestamp to the current time. This shows that this person keeps a chat window open and is displayed as online in the users section.



Chat.class.php – Part 1


Code:
/* The Chat class exploses public static methods, used by ajax.php */

class Chat{

    public static function login($name,$email){
        if(!$name || !$email){
            throw new Exception('Fill in all the required fields.');
        }

        if(!filter_input(INPUT_POST,'email',FILTER_VALIDATE_EMAIL)){
            throw new Exception('Your email is invalid.');
        }

        // Preparing the gravatar hash:
        $gravatar = md5(strtolower(trim($email)));

        $user = new ChatUser(array(
            'name'        => $name,
            'gravatar'    => $gravatar
        ));

        // The save method returns a MySQLi object
        if($user->save()->affected_rows != 1){
            throw new Exception('This nick is in use.');
        }

        $_SESSION['user']    = array(
            'name'        => $name,
            'gravatar'    => $gravatar
        );

        return array(
            'status'    => 1,
            'name'        => $name,
            'gravatar'    => Chat::gravatarFromHash($gravatar)
        );
    }

    public static function checkLogged(){
        $response = array('logged' => false);

        if($_SESSION['user']['name']){
            $response['logged'] = true;
            $response['loggedAs'] = array(
                'name'        => $_SESSION['user']['name'],
                'gravatar'    => Chat::gravatarFromHash($_SESSION['user']['gravatar'])
            );
        }

        return $response;
    }

    public static function logout(){
        DB::query("DELETE FROM webchat_users WHERE name = '".DB::esc($_SESSION['user']['name'])."'");

        $_SESSION = array();
        unset($_SESSION);

        return array('status' => 1);
    }



This is where all the work gets done. Remember the switch statement in ajax.php above? It maps the supported actions with the corresponding methods from this class. Each of these methods returns an array, as it is later converted to a JSON object with the internal json_encode() function (this happens at the bottom of ajax.php).


When the user logs in, their name and gravatar get saved as elements of the $_SESSION array, and become available on consecutive requests. We will be using this to validate that the user is allowed to add chats later on.

You can also see how we are preparing the gravatar hash. This is done according to their best practices guide and ensures that if the person has configured a Gravatar, it will be properly displayed.




Chat.class.php – Part 2



Code:
    public static function submitChat($chatText){
        if(!$_SESSION['user']){
            throw new Exception('You are not logged in');
        }

        if(!$chatText){
            throw new Exception('You haven\' entered a chat message.');
        }

        $chat = new ChatLine(array(
            'author'    => $_SESSION['user']['name'],
            'gravatar'    => $_SESSION['user']['gravatar'],
            'text'        => $chatText
        ));

        // The save method returns a MySQLi object
        $insertID = $chat->save()->insert_id;

        return array(
            'status'    => 1,
            'insertID'    => $insertID
        );
    }

    public static function getUsers(){
        if($_SESSION['user']['name']){
            $user = new ChatUser(array('name' => $_SESSION['user']['name']));
            $user->update();
        }

        // Deleting chats older than 5 minutes and users inactive for 30 seconds

        DB::query("DELETE FROM webchat_lines WHERE ts < SUBTIME(NOW(),'0:5:0')");
        DB::query("DELETE FROM webchat_users WHERE last_activity < SUBTIME(NOW(),'0:0:30')");

        $result = DB::query('SELECT * FROM webchat_users ORDER BY name ASC LIMIT 18');

        $users = array();
        while($user = $result->fetch_object()){
            $user->gravatar = Chat::gravatarFromHash($user->gravatar,30);
            $users[] = $user;
        }

        return array(
            'users' => $users,
            'total' => DB::query('SELECT COUNT(*) as cnt FROM webchat_users')->fetch_object()->cnt
        );
    }

    public static function getChats($lastID){
        $lastID = (int)$lastID;

        $result = DB::query('SELECT * FROM webchat_lines WHERE id > '.$lastID.' ORDER BY id ASC');

        $chats = array();
        while($chat = $result->fetch_object()){

            // Returning the GMT (UTC) time of the chat creation:

            $chat->time = array(
                'hours'        => gmdate('H',strtotime($chat->ts)),
                'minutes'    => gmdate('i',strtotime($chat->ts))
            );

            $chat->gravatar = Chat::gravatarFromHash($chat->gravatar);

            $chats[] = $chat;
        }

        return array('chats' => $chats);
    }

    public static function gravatarFromHash($hash, $size=23){
        return 'http://www.gravatar.com/avatar/'.$hash.'?size='.$size.'&default='.
                urlencode('http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size='.$size);
    }
}



As you will see in the next part of this tutorial, jQuery sends a getUsers() request every 15 seconds. We are using this to delete chats older than 5 minutes and inactive users from the database. We could potentially delete those records in getChats, but that is requested once every second and the extra processing time could severely impact the performance of our app.



Another thing worth noting, is that, in the getChats() method, we are using the gmdate function to output a GMT time. In the frontend, we use the hour and minute values to feed the JavaScript date object, and as a result all the times are displayed in the user’s local time.


With this the first part of this tutorial is complete!
 
Last edited:
Making an AJAX Web Chat (Part 2) – CSS and jQuery



1220.jpg




Now lets continue from where we left off last time.



CSS


The chat styles are self-contained and reside in chat.css. These styles are independent from the rest of the page, so it is easier to embed the chat window into an existing website. You just need to include the HTML markup we discussed last week, and include the stylesheet and JavaScript files.



chat.css – Part 1


Code:
/* Main chat container */

#chatContainer{
    width:510px;
    margin:100px auto;
    position:relative;
}

/* Top Bar */

#chatTopBar{
    height:40px;
    background:url('../img/solid_gray.jpg') repeat-x #d0d0d0;
    border:1px solid #fff;
    margin-bottom:15px;
    position:relative;

    color:#777;
    text-shadow:1px 1px 0 #FFFFFF;
}

#chatTopBar .name{
    position:absolute;
    top:10px;
    left:40px;
}

#chatTopBar img{
    left:9px;
    position:absolute;
    top:8px;
}

/* Chats */

#chatLineHolder{
    height:360px;
    width:350px;
    margin-bottom:20px;
    outline:none;
}

.chat{
    background:url('../img/chat_line_bg.jpg') repeat-x #d5d5d5;
    min-height:24px;
    padding:6px;
    border:1px solid #FFFFFF;

    padding:8px 6px 4px 37px;
    position:relative;
    margin:0 10px 10px 0;
}

.chat:last-child{
    margin-bottom:0;
}

.chat .gravatar{
    background:url('http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size=23') no-repeat;
    left:7px;
    position:absolute;
    top:7px;
}

.chat img{
    display:block;
    visibility:hidden;
}



We start off by styling the #chatContainer div. It is horizontally centered on the page, with the help of an auto margin. As you saw in the previous part of the tutorial, this div is further divided into a top bar, chats area, user area, and the bottom bar.


The top bar displays the user’s login information. It is assigned a relative positioning so that the avatar, name and logout button can be positioned accordingly.

After this comes the div that holds all of the chats – #chatLineHolder. This div has a fixed width and height, and as you will see in the jQuery part of this tutorial, we are using the jScrollPane plugin to turn it into a fancy scrollable area with custom sidebars.



ajax_web_chat_php_mysql_jQuery1.jpg




chat.css – Part 2



Code:
/* Chat User Area */

#chatUsers{
    background-color:#202020;
    border:1px solid #111111;
    height:360px;
    position:absolute;
    right:0;
    top:56px;
    width:150px;
}

#chatUsers .user{
    background:url('http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size=30') no-repeat 1px 1px #444444;
    border:1px solid #111111;
    float:left;
    height:32px;
    margin:10px 0 0 10px;
    width:32px;
}

#chatUsers .user img{
    border:1px solid #444444;
    display:block;
    visibility:hidden;
}

/* Bottom Bar */

#chatBottomBar{
    background:url('../img/solid_gray.jpg') repeat-x #d0d0d0;
    position:relative;
    padding:10px;
    border:1px solid #fff;
}

#chatBottomBar .tip{
    position:absolute;
    width:0;
    height:0;
    border:10px solid transparent;
    border-bottom-color:#eeeeee;
    top:-20px;
    left:20px;
}

#submitForm{
    display:none;
}





In the second part we style the #chatUsers container and the user divs. Each active chat user is represented by a 32 by 32 px gravatar. The default one is defined as a background, and when the real background images are loaded, they are shown above them. This prevents the annoying flickering that would usually occur before the image is loaded.



The rest of the code deals with the bottom bar and the submit forms. You may find interesting the way the .tip div is turned into a pure CSS triangle using a zero height and width, along with a large border value. We’ve used this trick in previous tutorials as well.



chat.css – Part 3



Code:
/* Overriding the default styles of jScrollPane */

.jspVerticalBar{
    background:none;
    width:20px;
}

.jspTrack{
    background-color:#202020;
    border:1px solid #111111;
    width:3px;
    right:-10px;
}

.jspDrag {
    background:url('../img/slider.png') no-repeat;
    width:20px;
    left:-9px;
    height:20px !important;
    margin-top:-5px;
}

.jspDrag:hover{
    background-position:left bottom;
}

/* Additional styles */

#chatContainer .blueButton{
    background:url('../img/button_blue.png') no-repeat;
    border:none !important;
    color:#516D7F !important;
    display:inline-block;
    font-size:13px;
    height:29px;
    text-align:center;
    text-shadow:1px 1px 0 rgba(255, 255, 255, 0.4);
    width:75px;
    margin:0;
    cursor:pointer;
}

#chatContainer .blueButton:hover{
    background-position:left bottom;
}



In the last part of the code, we override the default styling of the jScrollPane div. By default it is shown with purple scrollbars, which is not very suitable for our design. Instead of coding our own stylesheet from scratch, we just include the default one and override some of the rules.


Lastly, you can see the styles of the blue button. You can assign this class to any regular anchor or button, and you will get a pretty blue button.



jQuery




Moving to the last step of this tutorial – the jQuery code. The chat works by listening for events on the login and submit forms (and the logout button), and by scheduling AJAX request back to the server for checking for new chats and users.



As you saw in the first part of the tutorial last week, on the PHP side the AJAX requests are handled by ajax.php. jQuery issues a number of AJAX requests:
.Logging a user in: this is done by a single POST request;
.Logging a user out: also a single POST request;
.Checking for logged in users: this is done once every 15 seconds;
.Checking for new chats: a GET request is fired every second. This could potentially mean a heavy load on your webserver, this is why the script is optimized on the back end, and depending on the activity of the chat, requests are decreased to one every 15 seconds.



As you will see in the code below, we’ve defined custom wrapper for jQuery’s $.get and $.post AJAX functions, which will aid us in not having to fill in all the lengthy parameters for issuing a request.



Also, all of the chat code is organized in a single object called chat. It consists of a number of useful methods, which you will see in the fragments below.



script.js – Part 1


Code:
$(document).ready(function(){

    chat.init();

});

var chat = {

    // data holds variables for use in the class:

    data : {
        lastID         : 0,
        noActivity    : 0
    },

    // Init binds event listeners and sets up timers:

    init : function(){

        // Using the defaultText jQuery plugin, included at the bottom:
        $('#name').defaultText('Nickname');
        $('#email').defaultText('Email (Gravatars are Enabled)');

        // Converting the #chatLineHolder div into a jScrollPane,
        // and saving the plugin's API in chat.data:

        chat.data.jspAPI = $('#chatLineHolder').jScrollPane({
            verticalDragMinHeight: 12,
            verticalDragMaxHeight: 12
        }).data('jsp');

        // We use the working variable to prevent
        // multiple form submissions:

        var working = false;

        // Logging a person in the chat:

        $('#loginForm').submit(function(){

            if(working) return false;
            working = true;

            // Using our tzPOST wrapper function
            // (defined in the bottom):

            $.tzPOST('login',$(this).serialize(),function(r){
                working = false;

                if(r.error){
                    chat.displayError(r.error);
                }
                else chat.login(r.name,r.gravatar);
            });

            return false;
        });




The purpose of the init() method is to bind all event handlers for the chat and start the timeout functions that are used to schedule the checks for new chats and online users. You can see that we’ve used our own wrapper functions – $.tzGET and $.tzPOST. These lift the burden of having to specify a long list of parameters and targets for the ajax requests.



script.js – Part 2


Code:
    // Submitting a new chat entry:

    $('#submitForm').submit(function(){

        var text = $('#chatText').val();

        if(text.length == 0){
            return false;
        }

        if(working) return false;
        working = true;

        // Assigning a temporary ID to the chat:
        var tempID = 't'+Math.round(Math.random()*1000000),
            params = {
                id            : tempID,
                author        : chat.data.name,
                gravatar    : chat.data.gravatar,
                text        : text.replace(/</g,'<').replace(/>/g,'>')
            };

        // Using our addChatLine method to add the chat
        // to the screen immediately, without waiting for
        // the AJAX request to complete:

        chat.addChatLine($.extend({},params));

        // Using our tzPOST wrapper method to send the chat
        // via a POST AJAX request:

        $.tzPOST('submitChat',$(this).serialize(),function(r){
            working = false;

            $('#chatText').val('');
            $('div.chat-'+tempID).remove();

            params['id'] = r.insertID;
            chat.addChatLine($.extend({},params));
        });

        return false;
    });

    // Logging the user out:

    $('a.logoutButton').live('click',function(){

        $('#chatTopBar > span').fadeOut(function(){
            $(this).remove();
        });

        $('#submitForm').fadeOut(function(){
            $('#loginForm').fadeIn();
        });

        $.tzPOST('logout');

        return false;
    });

    // Checking whether the user is already logged (browser refresh)

    $.tzGET('checkLogged',function(r){
        if(r.logged){
            chat.login(r.loggedAs.name,r.loggedAs.gravatar);
        }
    });

    // Self executing timeout functions

    (function getChatsTimeoutFunction(){
        chat.getChats(getChatsTimeoutFunction);
    })();

    (function getUsersTimeoutFunction(){
        chat.getUsers(getUsersTimeoutFunction);
    })();

},



In the second part of the script, we continue with binding event listeners. In the submit form, you can see that when the user adds a new chat, a temporary one is created and shown immediately, without waiting for the AJAX request to complete. Once the write has completed, the temporary chat is removed from the screen. This gives users the feeling that the chat is lightning fast, while the real write is performed in the background.


Near the end of the init method, we run two self executing named functions. The functions themselves are passed as parameters to the respective chat.getChats() or chat.getUsers() method, so that additional timeouts can be scheduled (you can see this in part 5 of the code).
 
script.js – Part 3



Code:
// The login method hides displays the
// user's login data and shows the submit form

login : function(name,gravatar){

    chat.data.name = name;
    chat.data.gravatar = gravatar;
    $('#chatTopBar').html(chat.render('loginTopBar',chat.data));

    $('#loginForm').fadeOut(function(){
        $('#submitForm').fadeIn();
        $('#chatText').focus();
    });

},

// The render method generates the HTML markup
// that is needed by the other methods:

render : function(template,params){

    var arr = [];
    switch(template){
        case 'loginTopBar':
            arr = [
            '<span><img src="',params.gravatar,'" width="23" height="23" />',
            '<span class="name">',params.name,
            '</span><a href="" class="logoutButton rounded">Logout</a></span>'];
        break;

        case 'chatLine':
            arr = [
                '<div class="chat chat-',params.id,' rounded"><span class="gravatar">'+
                '<img src="',params.gravatar,'" width="23" height="23" '+
                'onload="this.style.visibility=\'visible\'" />',
                '</span><span class="author">',params.author,
                ':</span><span class="text">',params.text,
                '</span><span class="time">',params.time,'</span></div>'];
        break;

        case 'user':
            arr = [
                '<div class="user" title="',params.name,'"><img src="',params.gravatar,
                '" width="30" height="30" onload="this.style.visibility=\'visible\'"'+
                ' /></div>'
            ];
        break;
    }

    // A single array join is faster than
    // multiple concatenations

    return arr.join('');

},



Here the render() method deserves most of our attention. What it does, is assemble a template depending on the passed template parameter. The method then creates and returns the requested HTML code, incorporating the values of the second parameter – the params object as needed. This is used by most of the other methods discussed here.



script.js – Part 4



Code:
// The addChatLine method ads a chat entry to the page

    addChatLine : function(params){

        // All times are displayed in the user's timezone

        var d = new Date();
        if(params.time) {

            // PHP returns the time in UTC (GMT). We use it to feed the date
            // object and later output it in the user's timezone. JavaScript
            // internally converts it for us.

            d.setUTCHours(params.time.hours,params.time.minutes);
        }

        params.time = (d.getHours() < 10 ? '0' : '' ) + d.getHours()+':'+
                      (d.getMinutes() < 10 ? '0':'') + d.getMinutes();

        var markup = chat.render('chatLine',params),
            exists = $('#chatLineHolder .chat-'+params.id);

        if(exists.length){
            exists.remove();
        }

        if(!chat.data.lastID){
            // If this is the first chat, remove the
            // paragraph saying there aren't any:

            $('#chatLineHolder p').remove();
        }

        // If this isn't a temporary chat:
        if(params.id.toString().charAt(0) != 't'){
            var previous = $('#chatLineHolder .chat-'+(+params.id - 1));
            if(previous.length){
                previous.after(markup);
            }
            else chat.data.jspAPI.getContentPane().append(markup);
        }
        else chat.data.jspAPI.getContentPane().append(markup);

        // As we added new content, we need to
        // reinitialise the jScrollPane plugin:

        chat.data.jspAPI.reinitialise();
        chat.data.jspAPI.scrollToBottom(true);

    },



The addChat() method takes a parameter object with the content of the chat, author and gravatar, and inserts the new chat line in the appropriate place in the #chatContainer div. Each chat (if not a temporary one) has a unique ID which is assigned by MySQL. This id is assigned as a class name to the chat in the form of chat-123.




When the addChat() method is run, it checks whether the previous chat entry exists (for chat-123 it would check chat-122). If it exists, it inserts the new chat after it. If it doesn’t, it just appends it to the div. This simple technique manages to insert all the chats in the right order and keep them that way.



chat-user-timezone.jpg




script.js – Part 5


Code:
// This method requests the latest chats
    // (since lastID), and adds them to the page.

    getChats : function(callback){
        $.tzGET('getChats',{lastID: chat.data.lastID},function(r){

            for(var i=0;i<r.chats.length;i++){
                chat.addChatLine(r.chats[i]);
            }

            if(r.chats.length){
                chat.data.noActivity = 0;
                chat.data.lastID = r.chats[i-1].id;
            }
            else{
                // If no chats were received, increment
                // the noActivity counter.

                chat.data.noActivity++;
            }

            if(!chat.data.lastID){
                chat.data.jspAPI.getContentPane().html('<p class="noChats">No chats yet</p>');
            }

            // Setting a timeout for the next request,
            // depending on the chat activity:

            var nextRequest = 1000;

            // 2 seconds
            if(chat.data.noActivity > 3){
                nextRequest = 2000;
            }

            if(chat.data.noActivity > 10){
                nextRequest = 5000;
            }

            // 15 seconds
            if(chat.data.noActivity > 20){
                nextRequest = 15000;
            }

            setTimeout(callback,nextRequest);
        });
    },

    // Requesting a list with all the users.

    getUsers : function(callback){
        $.tzGET('getUsers',function(r){

            var users = [];

            for(var i=0; i< r.users.length;i++){
                if(r.users[i]){
                    users.push(chat.render('user',r.users[i]));
                }
            }

            var message = '';

            if(r.total<1){
                message = 'No one is online';
            }
            else {
                message = r.total+' '+(r.total == 1 ? 'person':'people')+' online';
            }

            users.push('<p class="count">'+message+'</p>');

            $('#chatUsers').html(users.join(''));

            setTimeout(callback,15000);
        });
    },



Here we are taking care of managing the AJAX requests. In the getChats() method, you can see that we are determining when to run the function again depending on the noActivity property of the local data object. On each request that does not return new chats, we increment the counter. If it reaches a certain threshold, the next request is delayed.



script.js – Part 6



Code:
    // This method displays an error message on the top of the page:

    displayError : function(msg){
        var elem = $('<div>',{
            id        : 'chatErrorMessage',
            html    : msg
        });

        elem.click(function(){
            $(this).fadeOut(function(){
                $(this).remove();
            });
        });

        setTimeout(function(){
            elem.click();
        },5000);

        elem.hide().appendTo('body').slideDown();
    }
};

// Custom GET & POST wrappers:

$.tzPOST = function(action,data,callback){
    $.post('php/ajax.php?action='+action,data,callback,'json');
}

$.tzGET = function(action,data,callback){
    $.get('php/ajax.php?action='+action,data,callback,'json');
}

// A custom jQuery method for placeholder text:

$.fn.defaultText = function(value){

    var element = this.eq(0);
    element.data('defaultText',value);

    element.focus(function(){
        if(element.val() == value){
            element.val('').removeClass('defaultText');
        }
    }).blur(function(){
        if(element.val() == '' || element.val() == value){
            element.addClass('defaultText').val(value);
        }
    });

    return element.blur();
}



And lastly these are our helper methods and functions. The displayError() method shows the friendly red bar at the top of the page if an error occurs. After this come our custom $.tzGET and $.tzPOST wrappers, and finally the defaultText plugin, which we developed a while back for showing placeholder text.


With this our AJAX chat is complete!
 

Attachments

  • ajax-chat.zip
    22.6 KB · Views: 108
Last edited:
:thanks:Bangis nito T.S. ano po mga application na needed para dito?
 
di pa nman tapos. kumain lng kaya ko. saka hirap maggawa ng thread na ganyan kahaba noh.

do ko na lalagay yung sources.. nauna ka na e

Ahh, di pa ba tapos? Akala ko kasi tapos na kasi nabasa ko na:

With this our AJAX chat is complete!

Sige, post mo na yung kasunod nyan. :yipee:
 
thank you sir... keep on sharing,,
 
Last edited:
alam niyo ba kung pano to iintegrate sa facebook?
 
alam niyo ba kung pano to iintegrate sa facebook?

Kelangan mo i-access ang Facebook API. Meron silang mga SDK na pwede nang magamit para mapadali yung pagconnect. At base sa setup mo, either PHP SDK or Javascript SDK ang pwede mo magamit.

Kadalasan, yung PHP SDK ang ginagamit para mas "tago" sa user ang implementation. Pero yung host ng demo site mo ay mukhang free at malaki ang chance na disabled ang mga networking features (cUrl, sockets, remote fopen, etc) so hindi mo magagamit ang PHP SDK. If that's the case, ang choice mo na lang ay Javascript SDK.

Maganda ang mga sample dun sa Javascript SDK documentation. Meron na dun kung paano mo ilalagay sa page yung javascript, paano ipapalogin yung user, paano kukuning yung name ng user, etc.
 
Kelangan mo i-access ang Facebook API. Meron silang mga SDK na pwede nang magamit para mapadali yung pagconnect. At base sa setup mo, either PHP SDK or Javascript SDK ang pwede mo magamit.

Kadalasan, yung PHP SDK ang ginagamit para mas "tago" sa user ang implementation. Pero yung host ng demo site mo ay mukhang free at malaki ang chance na disabled ang mga networking features (cUrl, sockets, remote fopen, etc) so hindi mo magagamit ang PHP SDK. If that's the case, ang choice mo na lang ay Javascript SDK.

Maganda ang mga sample dun sa Javascript SDK documentation. Meron na dun kung paano mo ilalagay sa page yung javascript, paano ipapalogin yung user, paano kukuning yung name ng user, etc.


maganda nyan sir. lagay ka ng turorial dito para madali nmin malaman.
 
Salamat dito TS. Actually parang copy paste lang ginawa mo :) pero atleast. hehe. Mukang may mali akong gniawa di ko mapagana, i'll integrate it to facebook din ^_^ para sa isang website ko
salamat
 
Back
Top Bottom