Drupal: ajax-автодополнение поиска

Date January 3rd, 2012 Author Vitaly Agapov


Правда иной раз гнётся, но никогда не ломается и всплывает поверх лжи, как масло — поверх воды.

– Мигель де Сервантес Сааведра

Как-то раз я уже писал про Ajax-автозаполнение (Ajax-autosuggest) своими силами. Там в комментариях было много возмущения из-за того, что никак не была рассмотрена серверная часть решения. Причины, по которым я о ней не писал, ясны: это абсолютное разнообразие возможных серверных решений. Например, мой Perl’овый cgi-скрипт никак не прояснил бы ситуацию человеку, работающему с PHP. А пример с серверной частью в виде модуля для Drupal совсем не поможет адепту Joomla. Но теперь моя совесть будет совсем чиста, так как я всё-таки опишу, как самостоятельно и с наименьшими трудозатратами сделать автодополнение для стандартного поиска в Drupal 7.

Конечно же, можно использовать любой модуль из целой россыпи соответствующих расширений для Drupal: Finder, AutoSuggest Search и многих других.  Но тут либо нет портированной версии для Drupal 7.x, либо в модуле нет нужной нам функциональности, либо он работает не совсем так, как мы хотим, либо просто у нас чешутся руки. В общем, хотим сделать по-своему. Хотя стоит отметить, что Finder очень и очень хорош.

Подготовительный этап

Для начала нам нужен div, в который будет выводиться результат поиска. Его можно добавить хуком hook_block_view(), можно сделать свой шаблон search-block-form.tpl.php, можно добавить объект с помощью javascript, или самое простое – добавить этот div прямо в свой шаблон page.tpl.php. В общем, добавляем в разметку страницы:

<div id=”ajaxsearchresult” style=”display:none;”>

Создание View

Можно, конечно, из своего модуля обращаться к базе напрямую и выбирать нужные нам значения по нужному нам фильтру, но мы договорились делать всё наиболее простым способом. Поэтому модуль Views – наш выбор. Его обвиняют в тяжести и медлительности, но зато он умеет делать всё, что нам может потребоваться для выборки результатов, и даже больше.

Наш view мы назовём ajaxfinder. Создадим путь к нему /ajaxfinder.  Формат – таблица.

Список полей – по своему усмотрению. Так как в моём случае Drupal работает с модулем Ubercart, то и набор полей соответствующий: изображение стиля uc_thumbnail (со значением “Display 1 value” в блоке “Multiple Field Settings”, чтобы выводить только одно изображение, если у ноды их несколько), заголовок и стоимость для продажи.

Фильтр – по опубликованным товарам и по самому главному критерию, заголовку.В свойствах фильтра по заголовку надо разрешить изменение критерия (Expose this filter to visitors) и указать оператор Contains или Starts With. Так мы сможем выбирать нужные ноды, указывая значение фильтра как атрибут запроса к странице. Имя атрибута будет соответствовать значению поля Filter identifier. В моём случае это title.

На данном этапе после сохранения View на странице mysitename.ru/ajaxfinder?title=test должны выводиться соответствующие ноды в соответствующем табличном виде.

Создание модуля

Всё остальное будет делать модуль. Назовём его ajaxsearch. В нём будут всего три файла: ajaxsearch.info, ajaxsearch.module и ajaxsearch.js. Если что, то положить их надо будет в директории ajaxsearch в sites/all/modules/.

ajaxsearch.info

name = "AJAX Search"
description = "AJAX autosuggest for products"
core = 7.x
files[] = ajaxsearch.module
scripts[] = ajaxsearch.js

ajaxsearch.module

<?php
/**
 * Implements hook_menu().
 */
function ajaxsearch_menu() {
  $items = array();
  $items['ajaxsearch/getblock'] = array(
    'page callback' => 'ajaxsearch_get_block',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}
function ajaxsearch_get_block( $s = '' ) {
    $viewName='ajaxfinder';
    $displayId='default';
    $view = views_get_view($viewName);
    $view->set_display($displayId);
    $view->set_exposed_input(array('title' => $s));
    $view->execute();
    $res = $view->preview();
    return drupal_json_output(array('products'=>$res));
    exit;
}
?>

Здесь реализация hook_menu создаёт адрес ajaxsearch/getblock, контекстные аргументы которой передаются в callback-функцию ajaxsearch_get_block. Эта функция уже получает View и отдаёт его в JSON-формате.

ajaxsearch.js

  var suggest_count = 0;
  Drupal.behaviors.ajaxsearch = {
    attach: function(context) {
        jQuery('*:not(#ajaxsearchresult)').click(function() {
                jQuery('#ajaxsearchresult', context).fadeOut();
        });
        jQuery('#ajaxsearchresult tr').click(function() {
                document.location = jQuery(this).find('a').attr('href');
        });
        jQuery('#block-search-form input', context).bind('keyup', function() {
                var s = jQuery(this).val();
                suggest_count++;
                setTimeout("searchGo("+suggest_count+")",300);

        });
    }
  };
  function searchGo(count) {
        if ( count == suggest_count ) {
                var s = jQuery('#block-search-form input').val();
                if (! s) { jQuery('#ajaxsearchresult').hide(); return; }
                var updateBlock = function(data) {
                        jQuery('#ajaxsearchresult').html(data.products);
                        if ( jQuery('#ajaxsearchresult .view-content').length > 0 ) 
                                jQuery("#ajaxsearchresult").show();
                                else jQuery("#ajaxsearchresult").hide();
                        Drupal.attachBehaviors('#ajaxsearchresult');
                }
                jQuery.ajax({
                   type: 'POST',
                   url: '/ajaxsearch/getblock/'+s,
                   success: updateBlock, 
                   dataType: 'json', 
                   data: 'js=1' 
                });
        }
  }

Это очень упрощённый для наглядности вариант скрипта с минимумом необходимой функциональности. При желании сделать полноценное решение можно обратиться к вышеупомянутой статье Ajax-автозаполнение (Ajax-autosuggest) своими силами.

Здесь же к объекту ‘#block-search-form input’ привязывается обработчик нажатия клавиш. Он ждёт 300 мс и, если новых нажатий за это время не было, то функция searchGo отправляет POST-запрос к нашей странице /ajaxsearch/getblock/ с соответствующим контекстным аргументом. Возвращаемое значение присваивается объекту ‘#ajaxsearchresult’, после чего тот отображается jQuery-методом show.

Не забыта необходимость закрыть всплывающее окно при клике в любую часть страницы и необходимость сделать переход на страницу ноды при клике на любую часть строки таблицы.

CSS

Само собой, надо стилизовать всплывающее окно. Тут полная свобода творчества, но две вещи обязательны:

Надо задать позиционирование блока:

#ajaxsearchresult { position: absolute; z-index:100; }

И спрятать форму для ручного ввода значения фильтра:

#ajaxsearchresult .view-filters { display: none; }

Конец

На этом всё. Отдыхаем, пьём морс.
Посмотреть рабочий вариант можно по адресу reactive-shop.ru.

Tags: , ,
Category: Drupal | 13 Comments »

Comments

13 комментариев на “Drupal: ajax-автодополнение поиска”

  1. derial

    Спасибо за статью.Очень полезная вещь, пригодится для любого магазина, фильтр в правой колонке магазина тоже понравился)

  2. Alex

    А можно узнать как реализован поиск по части слова на reactive-shop.ru?

  3. Vitaly Agapov

    Когда мы настраивали в нашем view критерии фильтра, то указали оператор “Contains”, который подразумевает поиск по части слова.

  4. Евгений

    По идее это ведь можно реализовать с помощью обычного поиска с подгрузкой результатов по ajax. Только блок с результатами позиционировать абсолютно относительнhttp://sweetcaptcha.s3.amazonaws.com/widget/v2/upload/answer_121.pngо формы поиска

  5. kstu

    А как сделать чтобы курсор после всплывания результатов поиска не исчезал, а оставался в поле поиска?

  6. Squiervxy

    ???????,??????????! .

  7. EOTechygi

    ???????,??????????! .

  8. Wirelessoot

    ???????,??????????! .

  9. Annotationsgqf

    ???????,??????????! .

  10. Xooyco

    i don’t unserstand that

  11. Johnnylor

    We organize compiled a cant of the superlative payday loan lenders uspaydayloansreviews.com after those times when a veritable danger hits, and your bad commendation prevents you from intriguing an crisis lend from elsewhere. To rank these payday lenders we scored them on how timely the allowance was deposited into an account, and how much fascinated by was added. We be struck by also provided a counsel on how to avoid the less over-nice lenders and also payday credit alternatives in regard to you to consider.

  12. Mickeylor

    If you’ve comprehend multitudes of cover company reviews insuranceforusa.org and peaceful can’t decide, it weight take to fall sundry quotes to compare. Depending on where you live and other factors, one-liner company could put forward a much superior deal on auto security than the rest.

  13. Rodionlor

    The unexcelled auto cover companies put on the market more than a gross percentage here: http://www.usinsurancereviews.com. They also promise ample coverage, open consumer support, and a clear, timely claims transform backed near stalwart financials. Six companies—USAA, Amica, Erie, Geico, Esurance, and Country Allotment—stood unconscious in our evaluation, but all 14 of our complete picks are principled providers worth considering.

Leave a comment

 Comment Form