Помогите сделать постраничный вывод сообщений в ajax-чате

Тема в разделе "JavaScript", создана пользователем verfaa, 27 май 2012.

Модераторы: ZiX
  1. verfaa

    verfaa

    Регистр.:
    29 янв 2007
    Сообщения:
    375
    Симпатии:
    41
    Нужно прикрутить на сайт знакомств вебмессенджер, где пользователи могли бы общаться один на один. Покопавшись в нете, ничего подходящего толком не нашев, я решил взять за основу чат, который подробно описан в этих двух уроках:
    http://ruseller.com/lessons.php?rub_id=37&id=757
    http://ruseller.com/lessons.php?rub_id=32&id=758

    Опыта в программировании у меня немного, а опыта работы с JS совсем мало, поэтому с доработкой скрипта до вебмессенджера возникли трудности. Скрипт с руселлера я немного переработал, убрал из него ненужные на мой взгляд куски кода, дописал свой код, в результате пользователи могут отправлять друг другу сообщения и получать их.
    Но в руселлерском чате не сделана постраничная навигация сообщений, в результате чего все сообщения сразу подгружаются на страницу. А сообщений может быть много, 1000 например или больше и все они будут пытаться загрузиться на страницу, будет не очень хорошо, нужна постраничная навигация, как это сделано на mamba.ru или loveplanet.ru

    Вот код, который я имею на данный момент:
    HTML + JS
    Код:
    <div id="chatContainer">
     
        <div id="chatTopBar" class="rounded"></div>
        <div id="chatLineHolder"></div>
     
        <div id="chatBottomBar" class="rounded">
            <div class="tip"></div>
     
            <form id="submitForm" method="post" action="">
                <textarea id="chatText" name="chatText" class="rounded" maxlength="255"></textarea><br />
                <input type="submit" class="blueButton" value="Send msg!" />
            </form>
     
        </div>
     
    </div>
     
    <div id="num_pages"></div>
     
     
     
    <script src="{$site_root}{$template_root}/js/im_jquery.mousewheel.js"></script>
    <script src="{$site_root}{$template_root}/js/im_jScrollPane.min.js"></script>
     
    <script type="text/javascript">
        $(document).ready(function(){
     
        // Запускаем метод init, когда документ будет готов:
        chat.init();
     
    });
     
    var chat = {
     
        // data содержит перменные для использования в классах:
     
        data : {
            lastID        : 0,
            noActivity    : 0
        },
     
        // Init привязывает обработчики событий и устанавливает таймеры:
     
        init : function(){
     
            // Конвертируем div #chatLineHolder в jScrollPane,
            // сохраняем API плагина в chat.data:
     
            chat.data.jspAPI = $('#chatLineHolder').jScrollPane({
                verticalDragMinHeight: 12,
                verticalDragMaxHeight: 12
            }).data('jsp');
     
            // Используем перменную working для предотвращения
            // множественных отправок формы:
     
            var working = false;
     
            // Отправляем данные новой строки чата:
     
            $('#submitForm').submit(function(){
     
                var text = $('#chatText').val();
     
                if(text.length == 0){
                    return false;
                }
     
                if(working) return false;
                working = true;
     
                // Генерируем временный ID для чата:
                var tempID = 't'+Math.round(Math.random()*1000000),
                    params = {
                        id            : tempID,
                        author        : chat.data.name,
                        gravatar    : chat.data.gravatar,
                        text        : text.replace(/</g,'&lt;').replace(/>/g,'&gt;')
                    };
     
                // Используем метод addChatLine, чтобы добавить чат на экран
                // немедленно, не ожидая заверщения запроса AJAX:
     
                chat.addChatLine($.extend({},params));
     
                // Используем метод tzPOST, чтобы отправить чат
                // черех запрос POST AJAX:
     
                $.tzPOST('submitChat',$(this).serialize(),function(r){
                    working = false;
         
                    $('#chatText').val('');
                    $('div.chat-'+tempID).remove();
         
                    params['id'] = r.insertID;
                    chat.addChatLine($.extend({},params));
                });
     
                return false;
            });
     
     
            // Самовыполняющиеся функции таймаута
     
            (function getChatsTimeoutFunction(){
                chat.getChats(getChatsTimeoutFunction);
            })();
     
     
     
        },
     
     
        // Метод render генерирует разметку HTML,
        // которая нужна для других методов:
     
        render : function(template,params){
     
            var arr = [];
            switch(template){
     
                case 'chatLine':
                    arr = [
                        '<div class="chat chat-',params.id,' rounded"><span class="author">',params.author,
                        ':</span><span class="text">',params.text,'</span><span class="time">',params.time,'</span></div>'];
                break;
     
            }
     
            // Единственный метод join для массива выполняется
            // бысстрее, чем множественные слияния строк
     
            return arr.join('');
     
        },
     
        // Метод addChatLine добавляет строку чата на страницу
     
        addChatLine : function(params){
     
            // Все показания времени выводятся в формате временного пояса пользователя
     
            var d = new Date();
            if(params.time) {
     
                // PHP возвращает время в формате UTC (GMT). Мы используем его для формирования объекта date
                // и дальнейшего вывода в формате временного пояса пользователя.
                // JavaScript конвертирует его для нас.
     
                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){
                // Если это первая запись в чате, удаляем
                // параграф с сообщением о том, что еще ничего не написано:
     
                $('#chatLineHolder p').remove();
            }
     
            // Если это не временная строка чата:
            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);
     
            // Так как мы добавили новый контент, нужно
            // снова инициализировать плагин jScrollPane:
     
            chat.data.jspAPI.reinitialise();
            chat.data.jspAPI.scrollToBottom(true);
     
        },
     
        // Данный метод запрашивает последнюю запись в чате
        // (начиная с lastID), и добавляет ее на страницу.
     
        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{
                    // Если нет записей в чате, увеличиваем
                    // счетчик noActivity.
         
                    chat.data.noActivity++;
                }
     
                if(!chat.data.lastID){
                    chat.data.jspAPI.getContentPane().html('<p class="noChats">Ничего еще не написано</p>');
                }
     
                // Устанавливаем таймаут для следующего запроса
                // в зависимости активности чата:
     
                var nextRequest = 1000;
     
                // 2 секунды
                if(chat.data.noActivity > 3){
                    nextRequest = 2000;
                }
     
                if(chat.data.noActivity > 10){
                    nextRequest = 5000;
                }
     
                // 15 секунд
                if(chat.data.noActivity > 20){
                    nextRequest = 15000;
                }
     
                setTimeout(callback,nextRequest);
            });
        },
     
        // Данный метод выводит сообщение об ошибке наверху страницы:
     
        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();
        }
    };
     
    // Формирование GET & POST:
     
    $.tzPOST = function(action,data,callback){
        $.post('im_ajax.php?action='+action+'&resp={$respondent}',data,callback,'json');
    }
     
    $.tzGET = function(action,data,callback){
        $.get('im_ajax.php?action='+action+'&resp={$respondent}',data,callback,'json');
    }
     
    </script>
    В скрипт айди пользователя, с которым общается юзер, я передаю в обычном GET-запросе, т.е. в анкете есть ссылка <a href='im.php?resp=29476'>написать сообщение</a> - юзер её кликает и попадает на страницу с чатом и начинает общение)

    im_ajax.php
    Код:
    <?php
     
    // Если к нам идёт Ajax запрос, то ловим его
    if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
     
    // тут подключаем базу данных, стартуем сессию, включаем необходимые библиотеки...
     
    $user = auth_index_user(); // Авторизуем юзера
    $id_user = intval($user[0]); // Тут будет айди юзера
     
     
    $response = array();
     
    switch($_GET['action']){
    //Добавляем сообщение в базу
    case 'submitChat':
    $strSQL = "INSERT INTO pro_im_lines (id_user, id_respondent, text)
                VALUES (
                    '".$id_user."',
                    '".mysql_real_escape_string($_REQUEST['resp'])."',
                    '".mysql_real_escape_string($_POST['chatText'])."'     
            )";
            $dbconn->Execute($strSQL);
     
    $rs = $dbconn->Execute("SELECT LAST_INSERT_ID() FROM pro_im_lines");
     
      $response = array(
                'status'    => 1,
                'insertID'  => $rs->fields[0]
            );
     
      break;
     
     
     
     
    case 'getChats':
    // Получаем сообщения из базы, которые мы отправляли
      // собеседнику и которые собеседник отправлял нам, только 10 последних!
    $strSQL = "(SELECT * FROM pro_im_lines WHERE
                            ((id_user='".$id_user."' AND
                            id_respondent='".intval($_REQUEST['resp'])."') OR
                            (id_user='".intval($_REQUEST['resp'])."' AND
                            id_respondent='".$id_user."')) AND
                            id > '".intval($_GET['lastID'])."' ORDER BY id DESC LIMIT 10)
                            ORDER BY id ASC";
     
     
            $rs = $dbconn->Execute($strSQL);
     
    $i = 0;
        $chats = array();
        while(!$rs->EOF){
            $row = $rs->GetRowAssoc(false);
            $chats[$i]["id"] = $row["id"];
            $chats[$i]["author"] = $row["id_respondent"];
            $chats[$i]["text"] = $row["text"];
            $chats[$i]["ts"] = $row["ts"];
            $chats[$i]["time"] = array(
                          'hours'    => gmdate('H',strtotime($chats[$i]["ts"])),
                          'minutes'  => gmdate('i',strtotime($chats[$i]["ts"]))
                            );
            $rs->MoveNext();
            $i++;
        }
      // В результате в массиве $chats окажутся все сообщения, которые мы отправляли
      // собеседнику и которые собеседник отправлял нам.
    // Этот массив мы отправляем обратно в JS ниже - echo json_encode($response);
     
     
     
     
        // А тут я пытался сделать постраничный вывод:
    // Выбираем все сообщения, которые мы отправляли друг другу
        $strSQL = "SELECT * FROM pro_im_lines WHERE
                            (id_user='".$id_user."' AND
                            id_respondent='".intval($_REQUEST['resp'])."') OR
                            (id_user='".intval($_REQUEST['resp'])."' AND
                            id_respondent='".$id_user."')";
        $rs = $dbconn->Execute($strSQL);         
        $row_count = $rs->RowCount(); //считаем число строк в таблице с сообщениями
        $pages = ceil($row_count/10);//определим количество страниц
        $pages_arr = array();
        if($pages>1){
        for($i=1;$i<=$pages;$i++){
        $pages_arr[] = "<a href=\"javascript:ajax_get_data('.$page-1.');\">'.$i.' </a>";
        }
      }
     
     
        $response = array('chats' => $chats, 'pages_arr' => $pages_arr);
        break;
     
    }
     
    echo json_encode($response);
     
    }
    ...
    ?>
    В результате в массив pages_arr попадают нужные элементы (вижу в файрбаге) - ссылки, но как их добавить на страницу ума не приложу. В JS в
    возвратную функцию пытался добавить
    for(var i=0;i<r. pages_arr.length;i++){
    $("#num_pages").appendTo(r.pages_arr);


    }
    но ничего не добавляет, а в файрбаге в firefox только ошибку вываливает((
    Подскажите плиз, как мне сделать постраничную навигацию в моем случае и чтобы когда пользователь кликает скажем на 5-ю страницу нужные сообщения через ajax подкружались в окно чата.
    И в целом по коду, может его можно оптимизировать как-то, удалить ненужные части или добавить что-то? Понимаю что много написал, очень надеюсь на помощь и советы...