Gavin Youker
Gavin Youker

Reputation: 314

PHP and AJAX message box scroll on user scroll?

I have a PHP message system that automatically scrolls to the bottom of the div every 200ms to show new message. My issue is that if a user tries scrolling up they are forced to the bottom every 200ms. What is a method I can use to prevent this?

HTML and JavaScript:

        <div id="tab3">
          <h2>Chat Room</h>

                <div id="c-input_wrap">
                    <div id="chatlog">
                        Loading chat please wait...
                    </div>

                <div id="chatwrap">
                    <div id="chatinput">
                    <form name="chatbox" class="userchat">
                        <input class="userchat" name="message" type="text" autocomplete="off" onkeydown="if (event.keyCode == 13) document.getElementById('chatbutton').click()" autofocus/><br>
                        <input class="userchat" id="chatbutton" name="submitmsg" type="button" onclick="submitChat()" value="Send" />
                    </form>
                    </div>
                </div>
            </div>
        </div>

<script>    
    var form = document.querySelector('form[name="chatbox"]');
    form.addEventListener("submit", function (event) {
        event.preventDefault();
    });

    function submitChat() {
        if(chatbox.message.value == '') {
            alert('Error: Missing Fields.');
            return;
        }
        var message = chatbox.message.value;
        var xmlhttp = new XMLHttpRequest();

        xmlhttp.onreadystatechange = function() {
            if(xmlhttp.readyState==4&&xmlhttp.status==100) {
                document.getElementById('chatlog').innerHTML = xmlhttp.responseText;
            }
        }

        xmlhttp.open('GET','chat.php?message='+message, true);
        xmlhttp.send();
        chatbox.reset();
    }

    $(document).ready(function(e) {
        $.ajax('logs.php', {
            ifModified: true,
            complete: function(jqxhrResponse) {
                $('#chatlog').html(jqxhrResponse.responseText);
                // scroll to the bottom here
                scrollToNewMessage();
            }
        })
    });

    var allowScroll = true;
    $('#chatlog').scroll(function() {
        allowScroll = isNearBottom();
    });

    function isNearBottom() {
        var leeway = 10;
        $(window).scroll(function() {
            return $(window).scrollTop() + $(window).height() > $(document).height() - leeway;
    });
}

function scrollToNewMessage() {
  if (allowScroll) {
    $("#chatlog").animate({ scrollTop: $('#chatlog').prop("scrollHeight")}, 1000);
  }
}
</script>

chat.php:

<?php
    error_reporting(E_ALL & ~E_NOTICE);
    session_start();

    if  (isset($_SESSION['id'])) {
        $userId = $_SESSION['id'];
        $username = $_SESSION['username'];
        $userLabel = $_SESSION['nickname'];
    }

    $connect = mysqli_connect("", "", "", "");
    mysqli_select_db($connect, "root");
    $message = $_REQUEST['message'];
    $date = date('m/d/y');
    $time = date('H:i:s');

    mysqli_query($connect, 
    "INSERT INTO chat (name, message, time, date) VALUES ('$userLabel', '$message', '$time', '$date')"
    );

    $result1 = mysqli_query($connect, "SELECT * FROM chat ORDER by id");
    while ($extract = mysqli_fetch_assoc($result1)) {
        echo $extract['name'] . ": " . $extract['message'];
    }
?>

logs.php:

<?php
    error_reporting(E_ALL & ~E_NOTICE);
    session_start();

    if  (isset($_SESSION['id'])) {
        $userId = $_SESSION['id'];
        $username = $_SESSION['username'];
        $userLabel = $_SESSION['nickname'];
    }

    $connect = mysqli_connect("", "", "", "root");
    mysqli_select_db($connect, "root");
    $day = date('m/d/y');
    $result1 = mysqli_query($connect, "SELECT * 
                                       FROM (SELECT * 
                                             FROM chat 
                                             WHERE date = '$day' 
                                             ORDER BY id DESC 
                                             LIMIT 100) x                                      
                                       ORDER BY id ASC
                                       ");

    while ($extract = mysqli_fetch_assoc($result1)) {
            echo "
            <div class='usermessage'>
                <div class='mheader'>
                    <h1 style='color:".$color."'>" . $extract['time'] . "</h1>
                    <h2 style='color:".$color."'>" . $extract['date'] . "</h2>
                    <h3 style='color:".$color."'>" . $extract['name'] . "</h3>
                </div>
                <p>" . $extract['message'] . "</p>
            </div>";
        }
?>

Upvotes: 0

Views: 908

Answers (1)

jcuenod
jcuenod

Reputation: 58435

1. When to Scroll

You don't need to scroll every 200ms, you only need to scroll when there is a new message. Doing this with load is a bit more difficult but jQuery's ajax function can help you out:

$.ajax('logs.php', {
  ifModified: true,
  complete: function(jqxhrResponse) {
    $('#chatlog').html(jqxhrResponse.responseText);
    // scroll to the bottom here
    scrollToNewMessage();
  }
})

1 and a half: If ifModified doesn't work for you, declare a variable somewhere (in your $(document).ready should be fine).

var currentMessageText = "";

Now do your own check whether there is anything modified and, if so, update accordingly:

complete: function(jqxhrResponse) {
  if (currentMessageText != jqxhrResponse.responseText)
  {
    currentMessageText = jqxhrResponse.responseText;
    $('#chatlog').html(currentMessageText);
  }
}

2. When not to scroll

Now you need to figure out when not to scroll. If the user scrolls up, then we want not to scroll. If the user scrolls back down though, we do. We can use jQuery's scroll event to figure out when the user has scrolled and test how close to the bottom s/he has gone.

var allowScroll = true;
$('#chatlog').scroll(function() {
  allowScroll = isNearBottom();
});

/* modified from http://stackoverflow.com/a/3898152/123415 */
function isNearBottom() {
  var leeway = 10;
  $(window).scroll(function() {
    return $(window).scrollTop() + $(window).height() > $(document).height() - leeway);
  });
}

I've given the user a bit of leeway not to be at the very bottom but maybe you want to adjust this.

3. Scroll to new Message

Now we just have to scroll when appropriate:

function scrollToNewMessage() {
  if (allowScroll) {
    $("#chatlog").animate({ scrollTop: $('#chatlog').prop("scrollHeight")}, 1000);
  }
}

disclaimer: I haven't tested the above code, if there's a problem, just leave a comment and I'll correct it.

Upvotes: 1

Related Questions