YUI: autocomplete
Что такое AJAX, наверное, уже знают все. (кто не знает, идет гуглить), А что такое YUI я рассказывал в прошлой статье
Итак, автокомплит это технология, по которой данные взятые, например из аджакса (это совершенно не обязательно) предлагаются пользователю для быстрого заполнения полей формы. Например, пользователь пишет в поле "город" несколько букв - "Сан" ему будут предложены варианты "Санкт-Петербург", "Сан-Франциско" и "Сан Ремо" и пользователь быстро может выбрать мышкой или с клавиатуры то что ему нравится.
Проблема один - AJAX. Надо писать frontend (javascript) приложение, для клиента основанное на классе JsHttpRequest и backend (например, на php) приложение с запросом к БД
Проблема два нарисовать красивый выпадающий список с навигацией с клавиатуры. Проблема собственно у ослика (как обычно) потому что он не обрабатывает нажатие стрелочек в отличие от всех других браузеров.
Кстати, как и в прошлой статье, я отнюдь не говорю что это либа это панацея всех проблем! например, она очень тяжелая. Но раз я уже начал писать, а вы читать... продолжим
подключаем либу
<script type="text/javascript" src="lib/yahoo/yahoo/yahoo.js"></script>
<script type="text/javascript" src="lib/yahoo/dom/dom.js"></script>
<script type="text/javascript" src="lib/yahoo/event/event.js"></script>
<script type="text/javascript" src="lib/yahoo/connection/connection.js"></script>
<script type="text/javascript" src="lib/yahoo/animation/animation.js"></script>
<script type="text/javascript" src="lib/yahoo/autocomplete/autocomplete.js"></script>
и css
#ysearchmod {position:relative;padding:1em;}
#firstname_root {z-index:3000;} /* for IE z-index of absolute divs inside relative divs issue */
#secondname_root {z-index:2000;} /* for IE z-index of absolute divs inside relative divs issue */
#lastname_root {z-index:1000;} /* for IE z-index of absolute divs inside relative divs issue */
.yui-ac-content {position:absolute;width:100%;border:1px solid #404040;background:#fff;overflow:hidden;z-index:9050;}
.ysearchquery {position:absolute;right:10px;color:#808080;z-index:10;}
.yui-ac-shadow {position:absolute;margin:.3em;width:100%;background:#a0a0a0;z-index:9049;}
ul {padding:5px 0;width:100%;}
li {padding:0 5px;cursor:default;white-space:nowrap;}
li.yui-ac-highlight {background:#a0a0a0;}
li.yui-ac-prehighlight {background:pink;}
Для тех кто заметил что этот css сильно отличается от предлагаемого YAHOO объясняю - так как они описывают каждый элемент уже при трех полях на ajaxe css станет пухлым и дохлым поэтому я вынес его в JavaScript
И еще на заметку я буду предлагать заполнять ФИО
Последний штрих рисуем HTML
<div id="firstname_root"><input type="text" name="firstname" id="firstname" value=""><div id="firstname_conteiner"></div><div>
<div id="secondname_root"><input type="text" name="secondname" id="secondname" value=""><div id="secondname_conteiner"><div id="firstname_conteiner"></div><div>
<div id="lastname_root"><input type="text" name="lastname" id="lastname" value=""><div id="firstname_conteiner"><div id="lastname_conteiner"></div><div>
А теперь в тегах <_script>...<_/script> описываем загрузчик, он же frontend приложение
// определяем именное пространство
YAHOO.namespace("AutoComplete");
/*
Грубо говоря если вы определите YAHOO.namespace("XXX");
то следующая строчка будет выглядеть так
YAHOO.XXX = function(input){
*/
// конструктор
YAHOO.AutoComplete = function(input){
var oACDS;
var oAutoComp;
var oDiv = null;
// CSS, вот сюда то я и вынес все излишнее свойства
if (oDiv=document.getElementById(input))
{
var rDiv = document.getElementById(input+'_root');
var cDiv = document.getElementById(input+'_conteiner');
oDiv.style.position = "absolute";
oDiv.style.width = "100%";
rDiv.style.height = "2em";
rDiv.style.position = "relative";
rDiv.style.margin_bottom = "1.5em";
rDiv.style.width = "100%";
cDiv.style.position = "absolute";
cDiv.style.top = "1.7em";
cDiv.style.width = "100%";
}
// заполняем первый объект oACDS, он у нас отвечает за AJAX
// адресс backend'a с параметрами
oACDS = new YAHOO.widget.DS_XHR("/backend.php", ["n", "t"]);
// вид ответа - простой текст - по одному варианту на строку
oACDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT;
// кеширование
oACDS.queryMatchSubset = true;
// время кеширования 60 сек
oACDS.maxCacheEntries = 60;
// этот параметр отвечает за дополнительные параметры в url, который запрашивается
//тоесть вместо /backend.php данные будут посланы на /backend.php?active=имя_поля
oACDS.scriptQueryAppend = '&active=' + input;
//заполняем второй объект отвечающий за autocomplete, ему по большому счету нужно только имя поля в
//котором должен работать скрипт
oAutoComp = new YAHOO.widget.AutoComplete(input,input+'_conteiner', oACDS);
// разделитель (по умолчанию дописывает в конце выбранного варианта ';')
oAutoComp.delimChar = "";
// задержка в секундах до отправки запроса
oAutoComp.queryDelay = 0;
// минимальная длина строки перед поиском
oAutoComp.minQueryLength=1;
// имя класса для выделенного варианта ответа
oAutoComp.prehighlightClassName = "yui-ac-prehighlight";
// отключает автокомплит в браузере чтоб он не мешал
oAutoComp.allowBrowserAutocomplete = false;
// можно еще поизвращаться с анимацией, но это вы сделаете сами
};
//ну и собственно стартуем скрипт по разу на каждое поле
YAHOO.AutoComplete('firstname')
Теперь backend надо написать, да?!
// я полностью писать не буду, просто объясню. Данные из аджакса приходят в кодировке UCS-2BE поэтому
// ее надо перекодировать в win-1251
// таблица символов
$unicode_to_cp1251_tbl = array(
0x0402 => "x80", 0x0403 => "x81", 0x201A => "x82", 0x0453 => "x83",
0x201E => "x84", 0x2026 => "x85", 0x2020 => "x86", 0x2021 => "x87",
0x20AC => "x88", 0x2030 => "x89", 0x0409 => "x8A", 0x2039 => "x8B",
0x040A => "x8C", 0x040C => "x8D", 0x040B => "x8E", 0x040F => "x8F",
0x0452 => "x90", 0x2018 => "x91", 0x2019 => "x92", 0x201C => "x93",
0x201D => "x94", 0x2022 => "x95", 0x2013 => "x96", 0x2014 => "x97",
0x2122 => "x99", 0x0459 => "x9A", 0x203A => "x9B", 0x045A => "x9C",
0x045C => "x9D", 0x045B => "x9E", 0x045F => "x9F", 0x00A0 => "xA0",
0x040E => "xA1", 0x045E => "xA2", 0x0408 => "xA3", 0x00A4 => "xA4",
0x0490 => "xA5", 0x00A6 => "xA6", 0x00A7 => "xA7", 0x0401 => "xA8",
0x00A9 => "xA9", 0x0404 => "xAA", 0x00AB => "xAB", 0x00AC => "xAC",
0x00AD => "xAD", 0x00AE => "xAE", 0x0407 => "xAF", 0x00B0 => "xB0",
0x00B1 => "xB1", 0x0406 => "xB2", 0x0456 => "xB3", 0x0491 => "xB4",
0x00B5 => "xB5", 0x00B6 => "xB6", 0x00B7 => "xB7", 0x0451 => "xB8",
0x2116 => "xB9", 0x0454 => "xBA", 0x00BB => "xBB", 0x0458 => "xBC",
0x0405 => "xBD", 0x0455 => "xBE", 0x0457 => "xBF", 0x0410 => "xC0",
0x0411 => "xC1", 0x0412 => "xC2", 0x0413 => "xC3", 0x0414 => "xC4",
0x0415 => "xC5", 0x0416 => "xC6", 0x0417 => "xC7", 0x0418 => "xC8",
0x0419 => "xC9", 0x041A => "xCA", 0x041B => "xCB", 0x041C => "xCC",
0x041D => "xCD", 0x041E => "xCE", 0x041F => "xCF", 0x0420 => "xD0",
0x0421 => "xD1", 0x0422 => "xD2", 0x0423 => "xD3", 0x0424 => "xD4",
0x0425 => "xD5", 0x0426 => "xD6", 0x0427 => "xD7", 0x0428 => "xD8",
0x0429 => "xD9", 0x042A => "xDA", 0x042B => "xDB", 0x042C => "xDC",
0x042D => "xDD", 0x042E => "xDE", 0x042F => "xDF", 0x0430 => "xE0",
0x0431 => "xE1", 0x0432 => "xE2", 0x0433 => "xE3", 0x0434 => "xE4",
0x0435 => "xE5", 0x0436 => "xE6", 0x0437 => "xE7", 0x0438 => "xE8",
0x0439 => "xE9", 0x043A => "xEA", 0x043B => "xEB", 0x043C => "xEC",
0x043D => "xED", 0x043E => "xEE", 0x043F => "xEF", 0x0440 => "xF0",
0x0441 => "xF1", 0x0442 => "xF2", 0x0443 => "xF3", 0x0444 => "xF4",
0x0445 => "xF5", 0x0446 => "xF6", 0x0447 => "xF7", 0x0448 => "xF8",
0x0449 => "xF9", 0x044A => "xFA", 0x044B => "xFB", 0x044C => "xFC",
0x044D => "xFD", 0x044E => "xFE", 0x044F => "xFF",
);
// функция поиска по таблице
function utf8_to_cp1251($s) {
$tbl = $GLOBALS['unicode_to_cp1251_tbl'];
$uc = 0;
$bits = 0;
$r = "";
for($i = 0, $l = strlen($s); $i < $l; $i++)
{
$c = $s{$i};
$b = ord($c);
if($b & 0x80)
{
if($b & 0x40)
{
if($b & 0x20)
{
$uc = ($b & 0x0F) << 12;
$bits = 12;
} else {
$uc = ($b & 0x1F) << 6;
$bits = 6;
}
} else {
$bits -= 6;
if($bits)
{
$uc |= ($b & 0x3F) << $bits;
} else {
$uc |= $b & 0x3F;
if($cc = @$tbl[$uc])
{
$r .= $cc;
} else {
$r .= '?';
}
}
}
} else {
$r .= $c;
}
}
return $r;
}
// применяем функцию ко всем входящим данным
foreach ($_REQUEST as $key => $value){
$_REQUEST[$key] = utf8_to_cp1251($value);
}
// из всех данный нужно только 2
$like = $_REQUEST['query'];
$field = $_REQUEST['active'];
// соединяемся с БД
mysql_connect('localhost','user','pass');
mysql_select_db('namedatabase');
//Ну и собственно спрашиваем есть ли похожие имена
$sql = mysql_query("SELECT ".$field." AS suggestion FROM table_name WHERE ".$field." LIKE '$like%' ORDER BY ".$field."LIMIT 50");
// выводим списком ответ
while($result = mysql_fetch_assoc($sql)){
echo $result['suggestion']."n";
}
Вот, пожалуй, и все. Кстати очень тяжелая (много килобайт весит) либа. Subsys от Котерова намного легче и практичнее, но не имеет автокомплита. Попытки втиснуть его туда насильно увенчались успехом только для FF1.5 и Opera8.0 , IE ругался
Свежие комментарии