AJAX и Vote Up Down

Есть такой модуль — Vote Up Down. Весьма полезный, когда речь заходит обо всяких рейтингах, кармах и прочих количественных измерениях деятельности пользователей на сайте. Сам по себе он (модуль) вполне адекватный, в особенности если использовать подмодуль vud_field. К слову, есть тенденция к замене всех составляющих Vote Up Down на одно это поле — вполне в духе седьмого Друпала.

Так или иначе, иногда требуется выполнить на сайте действия непосредственно после очередного пользовательского голоса. И получить по AJAXу ответ от сервера. Самый примитивный пример: голос за/против пользователя изменяет его рейтинг по определенной формуле — и нам надо обновить не только сам виджет голосовалки, но и рейтинг пользователя в каком-нибудь другом месте на странице.

Очевидно, нужно зацепиться в JavaScript-е за какое-нибудь событие. Можно было бы подвесить обработчик .click() на кнопках голоса, но не тут-то было: когда обработчику будет передан контроль — вновь созданный голос еще не будет сохранен на сайте, и следовательно данные, которые мы получим в ответ, не будут актуальными.

Но — есть в jQuery возможность зацепиться за ajaxComplete. Это событие происходит всякий раз, когда очередной запрос ajax был завершен. Посмотрим, как это применить к Vote Up Down.

PHP-часть, использующую ajax_command(), оставим за бортом: благо в интернете немало руководств на эту тему для Drupal 7. Например, раз и два. Перейдем сразу к JavaScript-у:

(function ($) {
  $(document).ready( function() {
    $(document).ajaxComplete(processAjaxCallback);
  });

  function updateRates() {
    //этот код отправит запрос по адресу /path/to/my/ajax
    //в ответ мы ожидаем JSON с командами
    var settings = {url : '/path/to/my/ajax'};
    var ajax = new Drupal.ajax(false, false, settings);    
    ajax.eventResponse(ajax, {});
  }

})(jQuery);

А теперь самое интересное — функция-обработчик события ajaxComplete. Первое, что нам нужно в ней сделать — это определить, что мы реагируем именно на событие голосования (мало ли какие еще ajax-вызовы у нас есть). Для этого у функции-обработчика есть аргумент: объект options, а точнее его свойство url. Это URL, по которому был совершен запрос — по нему-то мы и поймем, что имеем дело с нужным событием. URL-ов, по которым Vote Up Down отправляет голоса, два (они чуть-чуть отличаются). Нас в них интересуют — тип голоса (vote или votereset, последний это сброс голоса), сущность, за которую голосует пользователь (node, user, comment) и хэш. Хэш нужен, потому что, во-первых, модуль Vote Up Down использует его, чтоб отличать одно действие по голосованию от другого, и во-вторых — на случай повторных запросов. Итак, URL-ы вот такие:

  • vote/entitytype/%/%/%/%/hash/…
  • votereset/entitytype/%/%/%/hash/…

Код функции-обработчика:

function processAjaxCallback(event, response, options) {
    if (processAjaxCallback.voteHash == 'undefined') {
      //в статической переменной будем хранить хэш последнего запроса
      processAjaxCallback.voteHash = 'none';
    }
    var url_parts = options.url.split("/");
    //проверим, "наш" ли это запрос
    if ((url_parts[1] !== 'vote') && (url_parts[1] !== 'votereset')) {
      return ;
    }
    var newVoteHash;
    if (url_parts[1] == 'vote') {
      var newVoteHash = url_parts[7];
    } else {
      //как показано выше, в случае votereset хэш на другой позиции URL
      var newVoteHash = url_parts[6];
    }
    //если хэш отличается, значит это новый запрос - запускаем нужные действия
    if (processAjaxCallback.voteHash != newVoteHash) {
      updateRates();
      //и сохраняем новый хэш в статической переменной
      processAjaxCallback.voteHash = newVoteHash;
    }
    return ;
  }
})(jQuery);

Комментарии