Pull to refresh

Google Suggest в стиле HTML5

Reading time 5 min
Views 3.8K
Original author: Anne van Kesteren

Введение


HTML5 — следующая большая переделка HTML (и XHTML), и разрабатывается совместно группами WHATWG и W3C HTML WG (работа еще не завершена, но в этой статье мы будем называть её просто HTML5). Я уже описывал начала HTML-форм и возможные улучшения с помощью HTML5 в моей предыдущей статье, поэтому сейчас рассмотрю некоторые более сложные аспекты полей ввода в HTML5, и завершу примером, демонстрирующим простоту создания автодополняющегося поля ввода — коротким серверным скриптом и несколькими строчками разметки.

Обсуждаемые в этой статье инструменты являются частью спецификации Web Forms 2, которая будет интегрирована в черновик HTML5. (Вам нужно использовать последнюю версию Opera, предпочтительно 9.5, чтобы увидеть примеры в действии. К сожалению, на переднем крае технологий нам нужно делать оговорки касательно браузера.)

Комбо-боксы (input list)


Давайте сначала рассмотрим, как HTML5 работает с комбо-боксами.
<input list="languages" name="language">
<datalist id="languages">
<option value="Norwegian"></option>
<option value="Dutch"></option>
<option value="English"></option>
</datalist>

В старых браузерах эта разметка деградирует в простое текстовое поле ввода. В новых агентах, поддерживающих HTML5, вы сможете выбрать одно из предопределенных значений (в дополнение к возможности ввести произвольный текст). Эта функциональность очень похожа, например, на предлагаемую почтовыми клиентами или адресной строкой браузера. Если вам нужно именно это, но ещё вы хотите видеть в старых браузерах обычный выпадающий список (select) с вариантами, можете использовать такую разметку (в пример добавлен контекст):
<label>
Enter your front-end specialty:
<input list="languages" name="language">
</label>
<datalist id="languages">
<label>
or select one from the list:
<select name="language">
<option value="">(none)</option>
<option>HTML</option>
<option>CSS</option>
<option>JavaScript</option>
</select>
</label>
</datalist>

Браузеры с поддержкой атрибута list и элемента datalist из HTML5 не будут отображать элемент datalist со всем его содержимым. Вместо этого они будут использовать содержимое элементов option для заполнения комбо-бокса. Старые браузеры отобразят содержимое элемента datalist и позволят пользователю использовать либо текстовое поле, либо выпадающий список.

Внешний источник для datalist


Другая интересная особенность заключается в том, что подсказки могут быть взяты из внешнего XML-файла. Он должен отдаваться с медиа-типом application/xml и выглядеть приблизительно так:
<select xmlns="http://www.w3.org/1999/xhtml">
<option value="1"/>
<option value="2"/>
<option value="..."/>
</select>

Содержимое этого элемента select заменит содержимое любого элемента datalist, ссылающегося на файл, за исключением случая, когда у select атрибут type имеет значение incremental — тогда его содержимое будет не заменять существующие варианты, а дополнять их. Вы можете подключить внешний файл foo вот так:
<input list="languages" name="language">
<datalist id="languages" data="foo"></datalist>

(Кстати, у элемента select в HTML5 тоже есть атрибут data.)

Архив всего исходного кода статьи. Рабочий пример кода.

Динамический комбо-бокс


Мы рассмотрели комбо-боксы и способ заполнять их, используя внешний файл. Все, что нам теперь осталось до эмуляции Google Suggest в HTML5 — это ожидать события в комбо-боксе, и обращаться к маленькому серверному скрипту для динамического создания файла, который будет источником данных для элемента datalist. Чтобы сделать это обычными методами, вам нужно было бы создать свое собственное «выпадающее меню» со списком вариантов, использовать XMLHttpRequest для получения внешних данных, написать код, заполняющий этими данными меню — немалый труд, согласитесь.

Так какое событие мы можем использовать? В Web Forms 2 появилось новое событие input, которое уже поддерживается несколькими браузерами, включая Opera. Событие запускается после того, как пользователь вводит текст с клавиатуры. Если он быстро печатает много символов, запускается только одно событие. Подключение обработчика к комбо-боксу слегка усложняет код:

<input list=«suggest» name=«q»
oninput=«list.data = '?w=' + encodeURIComponent(value)»>
<datalist id=«suggest»></datalist>

Легко видеть, что обработчик события input изменяет list.data. Атрибут list поля ввода ссылается на элемент datalist по id, поэтому данные берутся именно из этого datalist. Все, что нам осталось сделать, чтобы загрузить данные с нужного адреса — это изменить атрибут data. Новый адрес — это строка ?w плюс строка, введенная пользователем, которую мы кодируем для использования в URI при помощи глобальной функции encodeURIComponent. Так что, если пользователь введёт foo, запрос будет отправлен по адресу ?w=foo (этот URI работает относительно страницы, на которой выполняется скрипт). Серверный скрипт получит этот URI, найдет текстовый файл с возможными вариантами для введенной строки, и потом вернет для заполнения комбо-бокса XML-файл, содержащий эти варианты. Всё это происходит динамически, поэтому как только вы измените искомый текст в текстовом поле, серверный скрипт обработает новые данные и отправит новый XML-файл, изменяя содержимое элемента datalist.

Я сделал рабочий пример этого для того, чтобы вы могли попробовать самостоятельно: загрузите файлы, или проверьте готовый пример в действии.

Файлы для этого примера:
  • список подсказок, разделенных переводами строки, в файле suggest.txt — он будет читаться серверным скриптом в поисках подходящих вариантов;
  • Python-скрипт article-example-suggest.py, который ищет в текстовом файле введенную пользователем строку, и потом возвращает XML с результатами поиска; также в этом файле описаны элементы input и datalist, которые мы обсуждали выше.

Полный код на python выглядит так:
import os
qs = os.environ["QUERY_STRING"]

# The page as shown by default
main="""Content-Type:texthtml;charset=UTF-8\n
<!doctype html>
<html>
<head><title>Demo</title></head>
<body>
<p>
<label>
Please enter a word:
<input list="suggest" name="q"
oninput="list.data = '?w=' + encodeURIComponent(value)">
</label>
<datalist id="suggest"></datalist>
</p>
</body>
</html>"""

if qs=="":
print main
else:
# If a query string was provided we need to provide an XML file with
# options filtered using the user input
import sys
print "Content-type: application/xml"
print "Cache-control: no-cache"
print ""
sys.stdout.write('<select xmlns="http://www.w3.org/1999/xhtml">')
sys.stdout.write(' <option>[searching for "%s"]</option>' % qs[2:])
for name in open('suggest.txt').readlines():
if name.lower().find(qs[2:].lower())!=-1:
sys.stdout.write('<option>%s</option>' % name)
sys.stdout.write('</select>')

Summary


Надеюсь, вам понравились эти примеры! (Огромное спасибо Johannes Hoff (Core developer в Opera) за создание этого Python-скрипта после того, как я намекнул в презентации, что с помощью HTML5 эмуляция Google Suggest — всего лишь несколько строчек, что оказалось правдой и на стороне сервера, и на стороне клиента.) Это еще не готово для серьезного использования, но даёт возможность почувствовать, что же мы получим с HTML5.
Tags:
Hubs:
+27
Comments 48
Comments Comments 48

Articles