Откроем Web-страницу index.htm в Блокноте, найдем созданный в главе 20 фраг-мент кода, создающий Web-форму поиска, и удалим его. Вместо него мы вставим
сразу после открывающего тега <BODY> код, приведенный в листинге 21.4.
Листинг 21.4
Он создает контейнер csearch, а в нем — Web-форму поиска. В Web-форме присут-ствуют те же элементы управления: поле ввода искомого слова, кнопка запуска по-иска и раскрывающийся список для выбора режима поиска. Ниже Web-формы мы
поместили список search_result, в котором будут выводиться результаты поиска.
Далее нам нужно задать стиль для только что созданного контейнера csearch, кото-рый сделает его свободно позиционируемым. Откроем таблицу стилей main.css
в Блокноте и добавим в нее CSS-код, приведенный в листинге 21.5.
Листинг 21.5
Здесь мы, собственно, делаем контейнер csearch свободно позиционируемым, зада-ем для него начальные координаты, внутренние отступы и рамку. Внутренние от-ступы будут совсем небольшими, чтобы контейнер сохранял компактность, а рам-ка — сплошной — пусть Web-форма поиска будет сразу заметна.
А еще мы указываем для контейнера csearch цвет фона — такой же, как у Web-страницы. Если мы этого не сделаем, фон контейнера будет прозрачным, и сквозь
него станет просвечивать содержимое Web-страницы, расположенное "ниже" кон-тейнера. А это будет выглядеть очень некрасиво.
Раз уж мы правим представление Web-страницы, давайте сразу зададим стили для
элементов управления и списка search_result, чтобы сделать их привлекательнее.
Рассмотрим эти стили отдельно друг от друга.
Мы задаем для абзаца, в котором поместили элементы управления, и списка
search_result нулевые внешние отступы, чтобы сделать контейнер csearch ком-пактнее:
#csearch P,
#search_result { margin: 0px }
Для элементов управления назначаем размер шрифта 10 пунктов:
INPUT, SELECT { font-size: 10pt }
Дело в том, что размер шрифта по умолчанию, принятый для элементов управле-ния, слишком мал, что понравится далеко не всем посетителям.
Убираем у пунктов списка search_result маркеры и слишком большой отступ сле-ва, где, собственно, выводятся эти маркеры:
#search_result LI { list-style-type: none;
margin-left: -40px; }
Так мы сделаем контейнер csearch еще компактнее.
На этом с Web-формой и элементами управления покончено.
Написание Web-сценария, выполняющего поиск
Осталось создать (точнее, переделать уже созданный в главе 20) Web-сценарий, ко-торый, собственно, будет выполнять поиск.
Откроем файл Web-сценария main.js в Блокноте и добавим в его начало такое вы-ражение:
var cSearchHeight = 0;
Оно объявляет служебную переменную, в которой будет сохранена изначальная
высота контейнера csearch. Это значение мы будем использовать для позициониро-вания данного контейнера. Его высота в процессе работы будет постоянно менять-ся, поэтому для его позиционирования нам понадобится изначальное значение вы-соты.
Далее найдем тело функции, передаваемой методу onReady объекта Ext. В самом его
начале поместим два выражения:
Ext.get("search_result").setDisplayed(false);
cSearchHeight = Ext.get("csearch").getHeight();
Первое выражение сразу скроет список search_result, а второе присвоит изначаль-ную высоту контейнера csearch объявленной ранее служебной переменной.
Функцию adjustContainers, задающую размеры контейнеров, мы объявили еще в
главе 16 и с тех пор ни разу к ней не возвращались. Настала пора внести в объявле-ние этой функции некоторые правки.
Вот выражения, которые мы добавим в самый конец adjustContainers:
var elCSearch = Ext.get("csearch");
elCSearch.setLocation(clientWidth — elCSearch.getWidth(),
Ext.get("cmain").getY() — cSearchHeight);
Они позиционируют контейнер csearch так, чтобы он в любом случае находился
над верхним левым углом контейнера cmain. Кстати, здесь используется значение
изначальной высоты контейнера csearch, которое мы сохранили ранее.
Теперь найдем объявление функции searchData, написанной нами в главе 16. Пере-делаем его так, как показано в листинге 21.6.
Листинг 21.6
Рассмотрим листинг 21.6 построчно.
Перед поиском нам нужно удалить все пункты, уже присутствующие в списке
search_result. Для этого мы сначала удаляем все обработчики событий, привязан-ные к гиперссылкам, находящимся в пунктах этого списка, а потом удаляем сами
пункты:
var elSearchResult = Ext.get("search_result");
elSearchResult.select("A").removeAllListeners();
elSearchResult.dom.innerHTML = "";
elSearchResult.setDisplayed(false);
Напоследок скрываем список search_result.
Обратим внимание, как выполняется удаление пунктов списка search_result. Из
главы 15 мы знаем, что объект Web-обозревателя HTMLElement поддерживает свой-ство innerHTML, хранящее HTML-код, создающий содержимое данного элемента
Web-страницы, в виде строки. Значит, чтобы удалить все содержимое данного эле-мента, мы можем получить соответствующий ему экземпляр объекта HTMLElement
(через свойство dom объекта Ext Core Element) и присвоить его свойству innerHTML
пустую строку. Что мы и делаем.
На этом выполнение функции searchData заканчивается.
Функция cleanupSamples, которую мы объявили в главе 16, удаляет обработчики
событий, привязанные к гиперссылкам раздела "См. также" и результатам поиска.
Найдем объявляющий ее код и удалим выражения, которые убирают обработчики
событий у гиперссылок результатов поиска, — ведь ранее мы поместили выпол-няющий это действие код в функцию searchData. После этого объявление функции
cleanupSamples будет выглядеть так, как в листинге 21.8.
Листинг 21.8
Так, бóльшую часть работы мы сделали. Осталось реализовать скрытие списка
search_result при щелчке на содержимом Web-страницы.
Вернемся к телу функции, передаваемой параметром методу onReady объекта Ext, и
добавим в его конец такое выражение:
Ext.getBody().on("click",
function(){ Ext.get("search_result").setDisplayed(false); });
Оно привязывает к событию click секции тела Web-страницы обработчик, который
скрывает список search_result.
В главе 15 мы узнали, что некоторые события, в том числе и click, имеют обыкно-вение всплывать из элементов, в которых они изначально возникли, в их родители,
затем — в родители их родителей и, наконец, в секцию тела Web-страницы. Обра-ботчик события click, который мы только что привязали к секции тела Web-страницы, сработает независимо от того, в каком элементе Web-страницы возникло
это событие, и список search_result в любом случае будет скрыт.
Но тут возникает очень неприятный момент: событие click кнопки запуска поиска
также рано или поздно всплывет в секцию тела Web-страницы. Давайте посмотрим,
что получится в результате. Посетитель нажмет кнопку запуска поиска, функция
searchData сформирует пункты списка результатов и откроет этот список, после
чего выполнится обработчик события click, привязанный нами к секции тела Web-страницы, который скроет список результатов. Непорядок!
Найдем в теле функции, передаваемой параметром методу onReady объекта Ext, вот
это выражение:
Ext.get("find").on("click", searchData);
Оно привязывает обработчик к событию click кнопки, запускающей поиск. Изме-ним его следующим образом:
Ext.get("find").on("click", function(e){
searchData();
e.stopPropagation();
});
Новый обработчик события click сначала вызовет функцию searchData, собственно
выполняющую поиск, а потом подавит всплытие возникшего события. Как видим,
для этого используется метод stopPropagation объекта Ext Core EventObject
(см. главу 15).
И еще. В обработчике события click пунктов полосы навигации (функция
loadFragment) у нас подавляется всплытие этого события. Следовательно, если по-сетитель щелкнет на пункте полосы навигации (или гиперссылке раздела
"См. также", или гиперссылке пункта в списке результатов поиска), событие click
не всплывет в секцию тела Web-страницы, привязанный к нему обработчик не вы-полнится, и список search_result скрыт не будет. Нам нужно это исправить.
Найдем код, объявляющий функцию loadFragment, и добавим в самый его конец
такое выражение:
Ext.get("search_result").setDisplayed(false);
Что оно делает, мы уже знаем.
Сохраним все исправленные файлы и проверим поиск в действии. Вот теперь он
выглядит вполне профессионально!..