Как стать автором
Обновить

Обновляем счётчик сообщений Вконтакте без перезагрузки страницы

Время на прочтение5 мин
Количество просмотров26K
Я пользуюсь той-самой-социальной-сетью по нескольким причинам, одна из которых — возможность обмена текстовыми сообщениями (некоторые мои знакомые принципиально не пользуются мессенжерами, приходится подстраиваться). Раньше приходилось постоянно обновлять страницу, чтобы узнать о новых сообщениях, не так давно, Вконтакте появился сервис мгновенных сообщений, но он мне сразу не пришёлся по душе и я решил автоматизировать процесс.

В этом топике я расскажу о своей реализации механизма обновления индикатора «Мои сообщения» без перезагрузки страницы. Хотите узнать подробности? Добро пожаловать под кат!

Теория


Скрипт реализован с помощью jQuery и подключается к сайту с помощью Greasemonkey.

Для начала, расскажу принцип действия на пальцах:
  • С определённым интервалом (для себя я установил 20 секунд) загружаем страницу с сообщенями с помощью AJAX
  • Находим количество непрочитанных сообщений
  • Если результат пункта 2 равен нулю, то меняем текст ссылки на «Мои сообщения»
  • Если реэультат отличен от нуля, то меняем текст на «Мои сообщения (N

Практика


Для того, чтобы внедрить скрипт на страницу, я, как пользователь Firefox, воспользовался плагином Greasemonkey. Насколько мне известно, существует версия Greasemonkey для Google Chrome, Opera сама умеет выполнять пользовательские скрипты, что называется, «из коробки». Думаю, адаптировать мой скрипт для Оперы и Хрома — дело недолгое и несложное.

Для того, чтобы Greasemonkey принял наш скрипт, он должен соответствовать двум критериям:
  • Имя скрипта должно иметь вид script_name.user.js
  • Перед телом скрипта необходимо написать заголовок, если Вы ещё не знаете, каким образом он должен формироваться, для начала ознакомьтесь с этим топиком


Заголовок для нашего скрипта:
// ==UserScript==
// @name DynamicVK
// @namespace vk.com/stryaponoff
// @description Makes VK dynamic
// @author stryaponoff
// @include *vk.com/*
// @include *vkontakte.ru/*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
// ==/UserScript==


Затем укажем временной интервал для проверки сообщений (в миллисекундах):
var RefreshInterval = 20000;


Впервые за время моего знакомства с JavaScript, мне понадобилось найти количество вхождений подстроки в строку. Каково же было моё удивление, когда я не нашёл соответствующей функции в JS. В итоге родился следующий код:
function SubStrCount(source, string)
{
    var pos = 0;
    var count = 0;
    var offset = -1;
    var len = 0;
    while ((offset = source.indexOf(string, offset + 1)) != -1)
    {
        if (len > 0 && (offset + string.length) > len) {
            return false;
        } else {
            count++;
        }
    }
    return count;
}

Принцип действия следующий — мы просто находим символ, с которого начинается первое вхождение подстроки string в строку source. Инкрементим счётчик. Затем повторяем то же самое, только за начало поиска берём не первый символ строки source, а следующий сразу за найденным нам вхождением. И так до тех пор, пока не переберём всю строку.

Дальше начинается самое интересное — пишем основную функцию нашего скрипта:
function CheckMail()
{
    // Получаем ссылку на нашу страницу сообщений
    var mail_href = $('#l_msg a').attr('href');
    
    // Получаем через AJAX её код
    $.get(mail_href, function(data)
    {
        // Находим количество непрочитанных сообщений
        var NewMessagesCount = SubStrCount(data, 'read=\\"0\\"');
        // Если количество новых сообщений не равно нулю, то
        if (NewMessagesCount != 0) {
            // Изменяем текст на "Мои Сообщения (N)"
            $('#l_msg a').html('Мои Сообщения (<b>' + NewMessagesCount + '</b>)');
        // В противном случае ...
        } else {
            // Изменяем на "Мои Сообщения"
            $('#l_msg a').html('Мои Сообщения');
        }
    });
}

Код, который приходит в качестве ответа на AJAX-запрос содержит экранированные кавычки (в частности, интересующий нас HTML-атрибут read="0" превращается в read=\"0\"). Поэтому, чтобы найти именно этот текст нам нужно искать его вместе со слэшами, для чего нам необходимо, по сути, «экранировать экранирование» :) Получаем read=\\"0\\".

Ну и, наконец, нам нужно вызвать нашу функцию в нужный момент. После загрузки страницы мы выполняем её один раз и устанавливаем интервал повторения вызова (напомню, в нашем случае — 20 секунд):
$(document).ready(function()
{
    CheckMail();
    setInterval(function() { CheckMail() }, RefreshInterval);
});

Слишком часто обновлять страницу тоже не следует, даже если Вас не заботит моральная сторона вопроса (при слишком частом обновлении, Вы создаёте дополнительную нагрузку на сервер — своеобразную мини-DoS-атаку). При превышении определённого лимита слишком частых запросов, запросы от Вас просто временно заблокируют.

Полный код скрипта

// ==UserScript==
// @name DynamicVK
// @namespace vk.com/stryaponoff
// @description Makes VK dynamic
// @author stryaponoff
// @include *vk.com/*
// @include *vkontakte.ru/*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
// ==/UserScript==

var RefreshInterval = 20000;

function SubStrCount(source, string)
{
    var pos = 0;
    var count = 0;
    var offset = 0;
    var len = 0;
    while ((offset = source.indexOf(string, offset + 1)) != -1)
    {
        if (len > 0 && (offset + string.length) > len) {
            return false;
        } else {
            count++;
        }
    }
    return count;
}

function CheckMail()
{
    var mail_href = $('#l_msg a').attr('href');
    
    $.get(mail_href, function(data)
    {
        var NewMessagesCount = SubStrCount(data, 'read=\\"0\\"');
        if (NewMessagesCount != 0) {
            $('#l_msg a').html('Мои Сообщения (<b>' + NewMessagesCount + '</b>)');
        } else {
            $('#l_msg a').html('Мои Сообщения');
        }
    });
}

$(document).ready(function()
{
    CheckMail();
    setInterval(function() { CheckMail() }, RefreshInterval);
});

Вариант скрипта без использования jQuery
(предпочтительный вариант, т.к. в нём исправлено множество ошибок)
// ==UserScript==
// @name DynamicVK
// @namespace vk.com/stryaponoff
// @description Makes VK dynamic
// @author stryaponoff
// @include *vk.com/*
// @include *vkontakte.ru/*
// ==/UserScript==

var RefreshInterval = 20000;

function CheckMail()
{
    // Создаём экземпляр AJAX-запроса
    var XmlHttp = new XMLHttpRequest();
    // Обнуляем количество сообщений
    var MsgCount = 0;
    
    // Эта функция выполняется при смене состояния запроса
    XmlHttp.onreadystatechange = function()
    {
        // Если запрос отправлен ...
        if (XmlHttp.readyState == 4)
        {
            // И страница успешно загрузилась, то ...
            if (XmlHttp.status == 200)
            {
                // Вычисляем количество непрочитанных сообщений
                var RegEx = /messages{count=(.*?)}/;
                MsgCount = RegEx.exec(XmlHttp.responseText)[1];
                
                // Передаю пламенный привет верстальщикам вконтакта
                // потому что вёрстка на разных страницах сайта разная
                // и нам придётся получить нужный нам элемент на обеих
                var sidebar;
                if (document.getElementById('side_bar') == null)
                {
                    sidebar = document.getElementById('sideBar');
                } else {
                    sidebar = document.getElementById('side_bar');
                }
                for (i = 0; i < sidebar.getElementsByTagName('a').length; i++)
                {
                    if (sidebar.getElementsByTagName('a')[i].href.indexOf('mail.php') != -1)
                    {
                        // Если кол-во сообщений не равно нулю, то ...
                        if (MsgCount != 0)
                        {
                            // Изменяем надпись на "Мои Сообщения (MsgCount)"
                            sidebar.getElementsByTagName('a')[i].innerHTML =
                               'Мои Сообщения <span>(<b>' + MsgCount + '</b>)</span>';
                        } else {
                            // Иначе изменяем на "Мои Сообщения"
                            sidebar.getElementsByTagName('a')[i].innerHTML = 'Мои Сообщения';
                        }
                        return;
                    }
                }
            }
        }
    }
    
    //Отправляем запрос на сервер
    XmlHttp.open('GET', '/feed.php', true);
    XmlHttp.send('');
}

CheckMail();
setInterval(function() { CheckMail() }, RefreshInterval);

Использование


Для того, чтобы использовать скрипт в браузере, просто перетащите файл скрипта (dynamicvk.user.js) в окно браузера, должно появиться следующее окно:

Всё, что от вас требуется — нажать «Install». Можете начинать пользоваться :)

Заключение


Надеюсь, данный топик окажется полезным кому-нибудь, кроме меня. В принципе, аналогичным образом можно обновлять и стену, и приглашения в друзья и прочие страницы, я лишь описал принцип действия. Рад буду выслушать конструктивную критику и замечания по поводу данного поста, чтобы не повторять ошибок в следующих публикациях. Также я благодарю всех, кто поднял мою карму и сделал возможной публикацию этого поста. Спасибо!

Если у кого-то возникнут вопросы или проблемы — пишите, попробуем разобраться. Спасибо за внимание!
Теги:
Хабы:
+5
Комментарии65

Публикации