Не удается правильно скопировать текст из-за повторяющегося вызова Ajax - PullRequest
0 голосов
/ 30 августа 2018

У меня есть простое веб-приложение для чата, и все работает. Однако есть две проблемы: 1) Когда я пытаюсь скопировать текст, повторяющийся вызов Ajax вызывает выделение всего текста, и GIF запускаются в цикле, если они длиннее интервала. 2) Уведомление о новом сообщении работает, но для того, чтобы новое сообщение было видно, вам нужно нажать на отправителя, даже если вы в данный момент разговариваете с ним.

enter image description here

Вот что происходит, когда я пытаюсь скопировать одно сообщение:

enter image description here

Я не могу понять, как получить новое сообщение для показа, не нажимая на ссылку пользователя.

Вот главная страница, chat.php:

<?php

//error_reporting(E_ERROR);
//ini_set('display_errors', 1);

include 'includes/header.php';
include 'includes/DB.php';

try {
    $db = new DB();
} catch (Exception $e) {
}

$username = $_SESSION['logged_in'];
$short_name = substr($username, 0, strpos($username, '.'));
?>
<div id="page-wrap">
    <h2 id="chat_title_h2">IT Chat</h2>
    <p id="name-area">Hello, <?= $short_name ?></p>
    <div id="chat-wrap">
        <div id="user-list">
            <p style="color:white;font: bold 12px 'Lucida Grande', Sans-Serif;margin-top:10px; margin-left:10px;">
                Conversations</p>
            <?php
            //Populate the user list
            foreach ($users_result = $db->getRows('SELECT * FROM users ORDER BY username', ['']) as $user) {
                $username = $user['username'];
                $short_list_name = substr($username, 0, strpos($username, '.'));
                echo '<p style="margin-left:10px;color:white;"><a class="link" style="color:white!important;" href=' . $username . '>' . $short_list_name . '</a><span class="dot" data-name="' . $username . '"</p>';
            }
            ?>
        </div>
        <div id="chat-area"></div>
    </div>
</div>

<div id="wrapper">
    <form name="message-form" id="message-form" method="post" enctype="multipart/form-data">
        <div class="input-group">
            <span class="input-group-addon" style="background-color:darkorange;color:white;font-size:18px;border:none;border-radius:0;">
            <label for="upload" style="margin-top:5px;font-size:20px;">
                <span class="fa fa-paperclip"></span>
                <input type="file" id="upload" name="upload" style="display:none;">
            </label>
            </span>
            <textarea id="message" class="form-control" rows="3" maxlength="50000" style="resize:none;margin:0;height:50px;"></textarea>
            <span class="input-group-addon btn btn-primary" id="send-button" style="background-color:darkorange!important;box-shadow:none!important;">Send</span>
        </div>
    </form>
</div>

<p class="input--error" style="visibility:hidden;">Error Uploading File</p>
<script>
    //var links = '<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">' + '<link rel="stylesheet" href="css/chat.css">';
    //$('head').append(links);

    //Disable send and upload buttons until user is clicked
    $('#message').prop('disabled', true);
    $('#upload').prop('disabled', true);
    $('#send-button').css('pointer-events', 'none');
    var userLink = '';
    document.title = 'Chat';

    //Check messges and notifications every 1000 ms
    setInterval(function () {
        getMessages();
    }, 1000); //<----- THE PROBLEM 
    setInterval(function () {
        checkNotifications();
    }, 1000);

    $(function() {
        //Function that defines what happens when a file is chosen from file chooser
        $('input:file').change(function () {
            var file_data = $('#upload').prop('files')[0];
            var form_data = new FormData();
            form_data.append('upload', file_data);
            $.ajax({
                url: 'includes/chat/upload.php?userLink='+userLink,
                type: 'post',
                data: form_data,
                contentType: false,
                cache: false,
                processData: false,
                success:function(data) {
                    if(data === 'Error') {
                        $('.input--error').css('visibility','visible');
                        $('.input--error').delay(3000).hide(0);
                    } else {
                        $('#chat-area').append(data);
                        var chatarea = $('#chat-area');
                        var height = chatarea[0].scrollHeight;
                        chatarea.scrollTop(height);
                    }
                },
                error:function(data) {
                    console.log(data);
                }
            })
        });
    });

    //Get messages to refresh chat window
    function getMessages() {
        if (userLink.length > 0) {
            $.ajax({
                url: 'includes/chat/get_messages.php?userLink=' + userLink,
                type: 'post',
                dataType: 'html',
                success: function (data) {
                    $('#chat-area').html(data);
                }
            })
        }
    }

    //If user's link is clicked, notification goes away and font changes to show which conversation you're on
    $(document).on('click', '.link', function (event) {
        event.preventDefault();

        //Scroll to the bottom when a user's link is clicked to read messages
        setTimeout(function() {
            var chatarea = $('#chat-area');
            var height = chatarea[0].scrollHeight;
            chatarea.scrollTop(height);
        }, 500);

        $('#message').prop('disabled', false);
        $('#upload').prop('disabled', false);
        $('#send-button').css('pointer-events', 'auto');
        userLink = $(this).attr('href');
        var name = userLink.substring(0, userLink.indexOf('.'));
        $('#message').attr('placeholder', 'Send message to ' + name);
        $('#message').addClass('message-placeholder');
        $('.message-placeholder').css('fontSize', 16);
        $('#chat_title_h2').text(name);
        $(this).parent().find('span').css('visibility', 'hidden');
        $(this).css({
            'font-weight': 'bold',
            fontSize: 18
        });
        $('.link').each(function () {
            if ($(this).attr('href') !== userLink) {
                $(this).css({
                    'font-weight': 'normal',
                    fontSize: 14
                })
            }
        });
        //Ajax call to get messages. Populate chat window with returned data
        $.ajax({
            type: 'post',
            url: 'includes/chat/show_conversation.php',
            data: {
                link: $(this).attr('href'),
            },
            dataType: 'html',
            success: function (data) {
                $('#chat-area').html(data);
            }
        })
    });
    //Button is not a 'button', but a span. Can't have a .submit() function here.
    $('#send-button').on('click', function () {
        var text = $('#message').val(); //Get what is in the textarea
        var maxLength = $('#message').attr('maxlength');
        console.log(text);
        var length = text.length;
        if (length <= maxLength + 1) { //Make sure it's not over the max length
            sendChat();
            $('#message').val('');
        } else {
            $('#message').val(text.substring(0, maxLength));
        }
    });

    //Ajax call to send the textarea data to the server. If overflow-y is present, auto-scroll to bottom
    function sendChat() {
        var text = $('#message').val();
        //Check to see if someone sent a link and format accordingly
        if (validURL(text)) {
            text = '<a target="_blank" href=' + text + '>' + text + '</a>';
        }
        $.ajax({
            url: 'includes/chat/send_message.php',
            type: 'post',
            data: {message: text, link: userLink},
            dataType: 'html',
            success: function (data) {
                getMessages();
                $('#chat-area').append(data);

                var chatarea = $('#chat-area');
                var height = chatarea[0].scrollHeight;
                chatarea.scrollTop(height);
            }
        });
    }
    //Check for new messages. Changes CSS of notification span to visible if new message is present.
    function checkNotifications() {
        $.ajax({
            url: 'includes/chat/check_notifications.php',
            type: 'post',
            dataType: 'json',
            success: function (data) {
                $.each(data, function (i, item) {
                    console.log(item);
                    $('.link').each(function () {
                        if ($(this).parent().find('span').data('name') === item) {
                            $(this).parent().find('span').css('visibility', 'visible');
                        }
                    })
                })
            }
        })
    }

    //Check if the message is a url so <a> tags can be added to the text
    function validURL(str) {
        var pattern = new RegExp('^((news|(ht|f)tp(s?)):\\/\\/)' + // protocol
            '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
            '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
            '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
            '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
            '(\\#[-a-z\\d_]*)?$', 'i'); // fragment locater
        if (!pattern.test(str)) {
            console.log('Not a valid URL');
            return false;
        } else {
            console.log('Valid URL');
            return true;
        }
    }
</script>
</body>
</html>

check_notifications.php

<?php

include '../DB.php';

try { $db = new DB(); } catch (Exception $e) { $e->getMessage(); }

session_start();

//This script checks for unread messages and shows notifications accordingly.
if(isset($_SESSION['logged_in'])) {
    $username = $_SESSION['logged_in'];
    $data = array();
    foreach($results = $db->getRows('SELECT user1, user2read FROM pm WHERE user2=?',[$username]) as $result) {
        $user2read = $result['user2read'];
        $user1 = $result['user1'];
        if($user2read === 'yes') {
            continue;
        }
        $data[] = $result['user1'];
    }
    echo json_encode($data);

}

get_messages.php

<?php
include '../DB.php';

try { $db = new DB(); } catch (Exception $e) { $e->getMessage(); }

session_start();
if(isset($_SESSION['logged_in'])) {
    $sender = $_SESSION['logged_in'];
    $recipient = $_GET['userLink'];

    foreach($results = $db->getRows('SELECT user1, user2, timestamp, message, user1read, user2read FROM pm WHERE (user1=? AND user2=?) OR (user1=? AND user2=?) ORDER BY id', [$sender, $recipient, $recipient, $sender]) as $result) {
        $user1 = $result['user1'];
        $user2 = $result['user2'];
        $short_name_1 = substr($user1, 0, strpos($user1, '.'));
        $message = $result['message'];
        $time = $result['timestamp'];
        $user1read = $result['user1read'];
        $user2read = $result['user2read'];

        echo '<p><strong>' . $short_name_1 . '</strong></p><p style="white-space:pre-wrap;padding: 2px 0;">' . $message . '</p><p style="padding: 2px 0; border-bottom: 1px solid #ccc;">' . $time . '</p>';
    }

}

show_conversation.php

<?php

include '../DB.php';

try { $db = new DB(); } catch (Exception $e) { $e->getMessage(); }

//This script shows the conversation when a user's link is clicked
session_start();
if($_SERVER['REQUEST_METHOD'] === 'POST') {
    if(isset($_SESSION['logged_in'])) {
        $username = $_SESSION['logged_in'];
        $recipient = $_POST['link'];

        foreach($results = $db->getRows('SELECT user1, user2, timestamp, message FROM pm WHERE (user1=? AND user2=?) OR (user1=? AND user2=?) ORDER BY id', [$username, $recipient, $recipient, $username]) as $result) {
            $user1 = $result['user1'];
            $user2 = $result['user2'];
            $short_name_1 = substr($user1, 0, strpos($user1, '.'));
            $message = $result['message'];
            $time = $result['timestamp'];
            echo '<p><strong>'.$short_name_1.'</strong></p><p style="white-space:pre-wrap;padding: 2px 0;">'.$message .'</p><p style="padding: 2px 0; border-bottom: 1px solid #ccc;">'.$time.'</p>';

        }
        $read_status_result = $db->updateRow('UPDATE pm SET user2read=? WHERE user2=?',['yes',$username]);
    }
}

send_message.php

<?php
include '../DB.php';
try { $db = new DB(); } catch (Exception $e) { $e->getMessage(); }

session_start();

if($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (isset($_SESSION['logged_in'])) {
        $user = $_SESSION['logged_in'];
        $message = $_POST['message'];
        $recipient = $_POST['link'];
        $timestamp = date('Y-m-d H:i:s');

        $short_name_1 = substr($user, 0, strpos($user, '.'));
        $short_name_2 = substr($recipient, 0, strpos($recipient, '.'));

        $result = $db->insertRow('INSERT INTO pm (user1, user2, message, timestamp, user1read, user2read) VALUES (?,?,?,?,?,?)', [$user, $recipient, $message, $timestamp, 'yes', 'yes']);
        echo '<p><strong>'.$short_name_1.'</strong></p><p style="white-space:pre-wrap;padding: 2px 0;">'.$message .'</p><p style="padding: 2px 0; border-bottom: 1px solid #ccc;">'.$timestamp.'</p>';
        $set_read_status_result = $db->updateRow('UPDATE pm SET user1read=?, user2read=? WHERE user1=? AND user2=?',['yes', 'no', $user, $recipient]);
    }
}

Есть еще один файл, upload.php, но он не актуален (если вы видите ссылку в строке запроса и задаетесь вопросом, куда она пошла).

Наконец, вот схемы для моих таблиц pm и users:

pm схема

mysql> describe pm;
+-----------+-------------+------+-----+-------------------+-----------------------------+
| Field     | Type        | Null | Key | Default           | Extra                       |
+-----------+-------------+------+-----+-------------------+-----------------------------+
| id        | int(11)     | NO   | PRI | NULL              | auto_increment              |
| user1     | varchar(30) | NO   |     | NULL              |                             |
| user2     | varchar(30) | NO   |     | NULL              |                             |
| message   | text        | YES  |     | NULL              |                             |
| timestamp | timestamp   | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| user1read | varchar(3)  | YES  |     | NULL              |                             |
| user2read | varchar(3)  | YES  |     | NULL              |                             |
+-----------+-------------+------+-----+-------------------+-----------------------------+
7 rows in set (0.01 sec)

Пользователи

mysql> describe users;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int(6)       | NO   | PRI | NULL    | auto_increment |
| username | varchar(255) | NO   |     | NULL    |                |
| password | varchar(255) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

По сути, было бы неплохо не проверять сообщения каждую секунду и просто заполнять их при отправке сообщения. Это не вредит этому проекту. Это скорее фактор удобства, но я уверен, что некоторые пользователи захотят эту функциональность.

Если что-то слишком расплывчато, или я что-то недостаточно хорошо прокомментировал, дайте мне знать, и я отредактирую.

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Хорошо, мне пришлось сделать некоторое жонглирование кодом, но я сделал это там, где теперь могу копировать текст, если это необходимо, и я просто отключил опцию загрузки GIF, так как анимация ужасна, так как setInterval выполняется каждую секунду. Пока это обходной путь, пока я не вернусь к нему, чтобы найти более постоянное решение.

Я присвоил переменную getMessages () setInterval и написал функции mouseup и mousedown:

 //Check messges and notifications every 1000 ms
var get_messages = setInterval(function () { //<-- Made this a variable
    getMessages();
}, 1000);
setInterval(function () {
    checkNotifications();
}, 1000);


$(function () {
    //Get the current mouse state to allow copying of text
    $('#chat-area').on('mousedown mouseup', function mouseState(e) {
        switch (e.type) {
            case 'mousedown':
                clearInterval(get_messages); //<-- Stop getting messages temporarily
                clearInterval(get_messages_again); //<-- Had to do it again with another variable
                console.log('Mouse down');
                break;
            case 'mouseup':
                console.log('Mouse up');
                setTimeout(function () { //<-- Give a few seconds to right click and Copy text, then go back to getting messages.
                    get_messages_again = setInterval(function () {
                        getMessages();
                    }, 1000);
                },3000);
                break;
        }
    });

Я также сделал так, чтобы уведомление ушло, если пользователь уже находится в разговоре с выбранным именем. Я просто добавил if / else к моей функции checkNotifications (), например так:

 //Check for new messages. Changes CSS of notification span to visible if new message is present.
function checkNotifications() {
    $.ajax({
        url: 'includes/chat/check_notifications.php',
        type: 'post',
        dataType: 'json',
        success: function (data) {
            $.each(data, function (i, item) {
                console.log(item);
                $('.link').each(function () {
                    //Get the current font-weight. 
                    //If it's above the norm, that means the user
                    //is currently viewing messages and a notification
                    //isn't needed.
                    if($(this).css('font-weight') > 400) {
                        $(this).parent().find('span').css('visibility', 'hidden');
                    } else {
                        //This code was already here. 
                        //Just made it part of the else statement
                        if ($(this).parent().find('span').data('name') === item) {
                            $(this).parent().find('span').css('visibility', 'visible');
                        }
                    }
                })
            })
        }
    })
}
0 голосов
/ 30 августа 2018

Решением для перезагрузки анимации (selection / gif-animation) было бы просто загрузить новые записи и оставить старые записи. Так что переписывание не будет сделано. Просто добавляю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...