Отправляет email-рассылки с помощью сервиса Sendsay

.NET: Записки программиста

  Все выпуски  

Свой Visual Search провайдер для IE 8 - задача на два помидора


Свой Visual Search провайдер для IE 8 - задача на два помидора

Visual Search Suggestions - одна из новых возможностей поиска в IE 8.0. Она позволит пользователям искать что-нибудь на вашем сайте, не переходя на его страницы. А если вы добавите к провайдеру favicon, ваш бренд (скорее брендик 16 на 16) всегда будет вместе с пользователем. Мини игры на Play2Game.ru А главное, она позволит разбавить сухой текст результатов поиска симпатичными картинками, например вот так:

А еще, вы сможете рассказать о своем провайдере, выложив его в галерею расширений IE 8.0. Или выиграть плазменный телевизор, поучавствовав в конкурсе дополнений к IE 8.0, который проводится в рамках конференции ReMIX09. конкурс расширений для IE 8.0

Между прочим, сейчас там зарегистрировано всего 3 визуальных провайдера, а сам конкурс продлится до 31 мая 2009. Так что если у вас есть что искать, а еще лучше - сайт с верной аудиторией, готовой поддержать его в конкурсе - давайте попробуем?

Сразу предупрежу, что от вас потребуется метод, который будет возвращать найденные по запросу данные. Как он будет выглядеть, зависит от ваших любимых технологий и размера сайта. В нашем примере (сайт с мини играми, который был написан на .NET) это было простое строковое стравнение в LINQ запросе. Кто-то посерьезнее настроит full text search в MS SQL Server, ну а приверженцы PHP и MySQL наверняка тоже смогут подобрать что-нибудь эффективное в своем арсенале.

Если у нас будет такой метод, все остальное - это задача на два помидора1. Причем, в отличие от web slices, простой вариант решения будет одновременно и хорошим, без всяких оговорок и нюансов.

Итак, в лучших традициях кулинарных программ, для успешного приготовления провайдера нам понадобится:
  • Сайт с картинками и текстом, которые мы сможем искать - 1 шт

  • Метод, который примет на вход строку, введенную пользователем в строке поиска и вернет нам немножко текста и картинок - 1 шт.

  • Модуль, к которому будет обращаться браузер, чтобы получить найденные результаты в xml формате - 1 шт

  • Еще немножко xml, чтобы описать наш провайдер - 1 шт

  • И для завершения - щепотка html, чтобы рассказать браузерам, какой чудесный провайдер мы приготовили
Ну что, продукты готовы, вода кипит - приступаем ... Сначала займемся основой нашего блюда - методом поиска, который собственно и будет выполнять всю реальную работу. Как мы и договаривались, его реализация полностью на вас. Абсолютно не важно, как это будет сделано, главное, чтобы он:
  1. Поиск на Play2Game.ru Принимал на вход текст, которую пользователь набрал в строке поиска:
    Причем учтите, браузер будет обращатся к вашему сайту после каждой введенной буквы, так что искать лучше побыстрее.

  2. Для каждого найденного элемента возвращал:

    • Заголовок

    • Краткое описание

    • URL страницы, на которую мы попадем выбрав этот элемент при поиске

    • URL картинки

    В принципе, достаточно возвращать только заголовок или url. Но если мы хотим получить красивый результат, нам понадобятся все элементы.
Переходим ко второй части: модулю вашего сайта, к которому будет обращаться браузер, чтобы получить xml с вариантами поиска. Формат вызова вы сможете задать сами, браузер всего лишь добавит к нему несколько параметров, описывающих запрос. Обязательно, нам понадобится только один параметр, в котором и будет передана строка поиска. Запрос может выглядеть примерно так:
http://{домен вашего сайта}/search.aspx?q={searchTerms}
Модуль может быть реализован по разному, например как IHttpModule или WebService. Я предпочел самый простой вариант - обычную html страницу:
<%@ Page Language="C#" CodeBehind="visual.aspx.cs" Inherits="Play2game.VisualProvider" %><?xml version="1.0"?>
<SearchSuggestion xmlns="http://schemas.microsoft.com/Search/2008/suggestions">
  <Query><asp:Literal ID="ltKeyword" runat="server"/></Query>
  <Section title="Варианты Play2Game.ru">
    <asp:Literal ID="ltItems" runat="server"/>
  </Section>
</SearchSuggestion>
Это xml, который нужно будет вернуть браузеру. Он содержит два placeholders (в виде простейших элементов управления ASP.NET Literal control). Вместо первого нам нужно будет вставить строку, которую искал пользователь. Браузер проверит ее и выведет результаты, только если эта строка совпадет со строкой, которую он передал в запросе.

Вместо второго placeholder мы подставим xml с описаниями найденных элементов. Перед тем как перейти к описанию этого xml, обратите внимание еще на две вещи:
  1. Строка <?xml version="1.0"?> находится в одной строке с декларацией страницы не случайно. Если вы напишите ее с новой строки (как сделал это я, так как ненавижу криво отформатированный текст), результирующий xml будет начинатся с символа перевода каретки и не будет распознан браузером (а вы увидите сообщение "ошибка", которое значит "у вас какие-то проблемы, попробуйте как-то изменить ваш код и попробовать снова")

  2. В теге Section мы передали название заголовка, которое будет выведено в самом начале, вместе с серой линией - разделителем. Если бы мы этого не сделали, IE сформировал его сам как "{Название вашего провайдера} вариантов", а это может выглядеть достаточно криво.
Теперь переходим к формату xml с самими результатами (который вставится на место второго placeholder). Он довольно простой:
<Item>
  <!-- Заголовок элемента -->
  <Text>То, не знаю что</Text>
  <!-- Описание элемента -->
  <Description>Это именно то, что ты искал.</Description>
  <!-- Url, на который мы перейдем, выбрав этот элемент -->
  <Url>/something.html</Url>
  <!-- Url картинки -->
  <Image source="/something.gif" alt="то, что ты искал" width="45" height="45" />
</Item>
...
<Separator title="Еще один список не знаю чего"/>
<Item>
  ...
</Item>
Тут тоже стоит обратить внимание на два момента. Первый - это размеры картинки. Если их указать - все будет работать отлично. Но если ваши изображения немного отличаются по размеру - это может стать проблемой. Если в обычном html в теге img вы указываете только один размер - ваше изображение будет пропорционально смасштабировано. Тут такой фокус не пройдет - картинки просто перестают показываться (когда я попробовал вообще не указывать размер, изображения нормально выводились при первом запросе после подключения провайдера, а потом все таки исчезли). Так что вам придется придумать, как правильно вычислять размеры.

В этом примере мне повезло - все иконки были одинакового размера 44 на 44. В другой раз было хуже, картинки попались разные и если указать что-то типа 45x45 - масштабировались в квадрат и безжалостно искажались. В конце концов, я добавил метод, который находил физический файл, определял его размеры и корректно проставлял аттрибуты width и height. Вопреки опасениям, работало это достаточно шустро - благодаря второму моменту, о котором мы сейчас поговорим.

Поиск игр на Play2Game.ru Дело в том, что размер списка ограничен - в нем будет выведено не более 10 элементов (поэтому проверить размеры максимум 10 файло было достаточно легко). Эти элементы можно выделять разделителями - тег <Separator title="Еще один список не знаю чего"/> в нашем xml. Однако резделители так же занимают одно из 10 мест. Так что вам нужно будет решить, выводить ли разделители, чтобы красиво сгруппировать найденные элементы или отобразить побольше результатов поиска.

XML с результатами поиска я создавал при помощи простого StringBuilder и вставлял на место placeholder. Если же вы сторонник сложных, но правильных решений, обязательно прочтите пост " Building an IE8 Visual Search Provider for my Twitter Friends" в котором Guy Burstein рассказывает, как правильно создавать такой модуль при помощи WCF REST service и XML serialization.

Почти все готово, осталось две мелочи. Первая - создать xml файл с описанием нашего провайдера:
<?xml version="1.0" encoding="utf-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:ie="http://schemas.microsoft.com/Search/2008/">
  <ShortName>{Название вашего провайдера}</ShortName>
  <Image height="16" width="16" type="image/icon">http://{доменное имя сайта}/favicon.ico</Image>
  <Url type="text/html" template="http://{доменное имя сайта}/search-page.aspx?q={searchTerms}"/>
  <Url type="application/x-suggestions+xml" template="http://{доменное имя сайта}/search.aspx?q={searchTerms}"/>
  <ie:PreviewUrl type="text/html" template="http://suggestions.example.com/search.aspx?q={searchTerms}"/>
</OpenSearchDescription>
На что стоит обратить внимание здесь:
  1. Тег <Url type="text/html" определяет url, который будет вызван, если пользователь просто нажмет ввод в строке поиска, так и не выбрав ни одного из вариантов в предложенном списке. Url вы можете указать произвольный, главное, чтобы он включал placeholder {searchTerms}, вместо которого браузер подставит введенную пользователем строку.
    Если на вашем сайте уже реализован поиск - направьте этот url туда. Если нет - доверьте это вашему любимому поисковому серверу, например вот так:
    <Url type="text/html" template="http://www.google.com/search?q={searchTerms}"/>
  2. Тег <Url type="application/x-suggestions+xml" определяет url нашего модуля, который должен вернуть xml с результатами. Условия те же: произвольный url с обязательным placeholder {searchTerms}, вместо которого браузер подставит строку для поиска. Кроме этого, в можете использовать еще несколько placeholders и тогда браузер передаст вам немного дополнительной полезной информации. Так, например, запрос вида:
    <Url type="text/html" template="http://www.google.com/search?q={searchTerms}&language={Language}"/>
    позволит вам узнать язык, установленный у пользователя (user's system's locale). А при помощи запроса:
    <Url type="text/html" template="http://www.google.com/search?q={searchTerms}&maxwidth={maxWidth}&rowheight={rowHeight}&sectionHeight={sectionHeight}"/>
    вы сможете получить точные размеры выпадающего окошка и лучше сформировать xml с результатами поиска. Подробное описание дополнительных параметров вы сможете найти в документации, ссылка на которую приведена в конце статьи.

  3. Все установленные поисковые провайдеры автоматически добавляются и как IE Accelerators (ускорители поиска, еще одна новинка IE 8.0). Поэтому, если пользователь выделит какой-то текст на странице сайта и вызовет список ускорителей - ваш поисковый провайдер тоже будет в этом списке. Строка:
    <ie:PreviewUrl type="text/html" template="http://suggestions.example.com/search.aspx?q={searchTerms}"/>
    позволяет указать url вашего сайта, который вернет html для отображения в preview окне ускорителя. Подробнее об ускорителях поиска вы сможете узнать в статье "OpenService Accelerators Developer Guide" из документации MSDN.
Последний штрих художника - добавим html тег с описанием провайдера в head нашего сайта. Выглядит он вот так:
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Play2Game.ru" />
Добавление поисквого провайдера Найдя его на нашем сайте, IE станет оранжевым от нетерпения и предложит добавить наш провайдер к уже зарегистрированным в нем поисковым провайдерам. Обратите внимание, значение аттрибута "Title" должно точно совпадать с аналогичным названием в теге "ShortName" описания провайдера. Если эти строки будут различатся, браузер не поверит, что уже добавил этот провайдер и будет предлагать добавить его снова.

Ну что, прошу к столу, вскипело!

А напоследок еще один совет, который поможет сделать приготовление провайдера более приятным. Браузер кеширует полученный xml, так что постоянно меняйте вводимые во время тестирования слова. Какое-то время я безуспешно пытался понять под отладчиком, почему же не вызывается мой модуль, когда я набираю классическое "sdfsdf" (еще варианты "йцукен" или "qwerty"). А если вам захочется разобраться во всех деталях - загляните в главную поваренную книгу Microsoft: Search Provider Extensibility in Internet Explorer и XML Search Suggestions Format Specification, а так же прочтите статью Себастьяна Циммермана (основного разработчика функции Visual Search) Hello, World или начинаем работать с IE8 Visual Search.

Приятной вам готовки и победы в конкурсе!


1 В XP время может измеряться в произвольных единицах, например баллах или Мишках Гамми. Мартин Фаулер как-то рассказывал о Франческо Чирилло, который купил и принес на работу тридцатиминутный кухонный таймер в форме помидора. С тех пор в команде появилось выражение «задачка на шесть помидоров».


блог сайта .NET: Записки программиста Подпишись на блог сайта .NET: Записки программиста

В избранное