К книге
HTML 5, CSS 3 и Web 2.0Часть 5 Последние штрихи. Глава 21 Свободно позиционируемые элементы Web-страницы. Реализация усовершенствованного поиска
86%
Часть 5 Последние штрихи. Глава 21 Свободно позиционируемые элементы Web-страницы. Реализация усовершенствованного поиска
133

Что ж, все, что нам нужно знать о свободно позиционируемых элементах, мы рассмотрели. Настала пора практических занятий.

В главе 20 мы реализовали на нашем Web-сайте систему поиска. Получилось, мягко говоря, не очень профессионально, о чем уже говорилось в начале этой главы. Давайте улучшим ситуацию.

Прежде всего, мы создадим новый контейнер, дадим ему имя csearch и поместим в него Web-форму поиска. В этот же контейнер, ниже Web-формы, мы вставим список, в котором будут выводиться результаты поиска. (Результаты мы будем формировать в виде пунктов списка, содержащих гиперссылки на найденные Web- страницы, — как и в главе 20.) Дадим этому списку имя search_result и сделаем его изначально скрытым.

Когда посетитель выполнит поиск, мы проверим, присутствуют ли в списке search_result какие-либо пункты (т. е. выполнялся ли поиск ранее и был ли он удачным), и, если присутствуют, удалим их и скроем этот список. Если поиск увенчался успехом, мы сформируем в списке search_result пункты, содержащие гиперссылки на найденные Web-страницы, и откроем его. Таким образом, список search_result будет присутствовать на экране только в случае успешного поиска.

Когда посетитель щелкнет на любом месте Web-страницы (неважно — на гиперссылке, в том числе и гиперссылке в списке результатов поиска, на абзаце, на изображении или вообще на пустом месте), мы должны скрыть список search_result. Это нужно для того, чтобы этот список не присутствовал на экране постоянно и не мешал посетителю.

В остальном новый поиск будет работать так же, как и старый.

Создание контейнера с Web-формой поиска

Откроем Web-страницу index.htm в Блокноте, найдем созданный в главе 20 фрагмент кода, создающий Web-форму поиска, и удалим его. Вместо него мы вставим сразу после открывающего тега <BODY> код, приведенный в листинге 21.4.

Листинг 21.4

<DIV ID="csearch">

<FORM ACTION="#">

<P>

<INPUT TYPE="search" ID="keyword" NAME="keyword" SIZE="20">

<INPUT TYPE="button" ID="find" NAME="find" VALUE="Искать!"><BR>

<SELECT ID="search_in" NAME="search_in">

<OPTION>В названиях</OPTION>

<OPTION>В ключевых словах</OPTION>

<OPTION SELECTED>В названиях и ключевых словах</OPTION>

</SELECT>

</P>

<UL ID="search_result">

</UL>

</FORM>

</DIV>

Он создает контейнер csearch, а в нем — Web-форму поиска. В Web-форме присутствуют те же элементы управления: поле ввода искомого слова, кнопка запуска поиска и раскрывающийся список для выбора режима поиска. Ниже Web-формы мы поместили список search_result, в котором будут выводиться результаты поиска.

Далее нам нужно задать стиль для только что созданного контейнера csearch, который сделает его свободно позиционируемым. Откроем таблицу стилей main.css в Блокноте и добавим в нее CSS-код, приведенный в листинге 21.5.

Листинг 21.5

#csearch { background-color: #F8F8F8; position: absolute;

left: 600px; top: 0px; padding: 2px; border: thin solid #B1BEC6 }

Здесь мы, собственно, делаем контейнер 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, написанной нами в главе 20. Переделаем его так, как показано в листинге 21.6.

Листинг 21.6

function searchData() {

var elSearchResult = Ext.get("search_result"); elSearchResult.select("A"). removeAllListeners(); elSearchResult.dom.innerHTML = ""; elSearchResult.setDisplayed(false);

var sKeyword = Ext.get("keyword"). getValue(false);

if (sKeyword!= "") {

var iSearchMode = Ext.getDom("search_in"). selectedIndex;

var aResult = [];

searchInArray(sKeyword, aHTML, aResult, iSearchMode); searchInArray(sKeyword, aCSS, aResult, iSearchMode); searchInArray(sKeyword, aSamples, aResult, iSearchMode); if (aResult.length > 0) {

var s = "";

for (var i = 0; i < aResult.length; i++) {

s += "<LI><A HREF=\"" + aResult[i].url + "\">" +

aResult[i].name + "</A></LI>";

}

var htelResult = elSearchResult.insertHtml("beforeEnd", s); Ext.fly(htelResult). select("A"). on("click", function(e, t) {

var href = Ext.fly(this). getAttribute("href");

var elA = Ext.get("navbar"). child("A[href=" + href + "]");

var elItem = elA.parent("LI");

loadFragment(elItem, e);

});

elSearchResult.setDisplayed(true);

}

}

Рассмотрим листинг 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 пустую строку. Что мы и делаем.

Листинг 21.7

var sKeyword = Ext.get("keyword"). getValue(false);

if (sKeyword!= "") {

var iSearchMode = Ext.getDom("search_in"). selectedIndex;

var aResult = [];

searchInArray(sKeyword, aHTML, aResult, iSearchMode); searchInArray(sKeyword, aCSS, aResult, iSearchMode); searchInArray(sKeyword, aSamples, aResult, iSearchMode); if (aResult.length > 0) {

var s = "";

for (var i = 0; i < aResult.length; i++) {

s += "<LI><A HREF=\"" + aResult[i].url + "\">" +

aResult[i].name + "</A></LI>";

}

var htelResult = elSearchResult.insertHtml("beforeEnd", s); Ext.fly(htelResult). select("A"). on("click", function(e, t) {

var href = Ext.fly(this). getAttribute("href");

var elA = Ext.get("navbar"). child("A[href=" + href + "]");

var elItem = elA.parent("LI");

loadFragment(elItem, e);

});

Фрагмент кода, приведенный в листинге 21.7, перекочевал из предыдущей реализации функции searchData практически без изменений. Мы уже знаем, что он делает. Сформировав пункты списка search_result, открываем его:

elSearchResult.setDisplayed(true);

}

}

На этом выполнение функции searchData заканчивается.

Функция cleanupSamples, которую мы объявили в главе 16, удаляет обработчики событий, привязанные к гиперссылкам раздела "См. также" и результатам поиска. Найдем объявляющий ее код и удалим выражения, которые убирают обработчики событий у гиперссылок результатов поиска, — ведь ранее мы поместили выполняющий это действие код в функцию searchData. После этого объявление функции cleanupSamples будет выглядеть так, как в листинге 21.8.

Листинг 21.8

function cleanupSamples() {

var ceSamples = Ext.select(".sample"); ceSamples.each(function(el, cl, ind){ var elH6 = el.child(":first"); elH6.removeAllListeners();

});

}

Так, бóльшую часть работы мы сделали. Осталось реализовать скрытие списка 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);

Что оно делает, мы уже знаем.

Сохраним все исправленные файлы и проверим поиск в действии. Вот теперь он выглядит вполне профессионально!..

Что дальше?

В этой главе мы познакомились со свободно позиционируемыми элементами Web- страницы и даже применили их на практике в новой версии системы поиска. Мелочь, конечно, — иные Web-дизайнеры с помощью свободных элементов творят на Web-страницах чудеса, — но для начала получилось неплохо.

В следующей, последней, главе мы познакомимся с еще одной возможностью HTML 5 — программируемой графикой. Мы научимся рисовать произвольные фигуры на Web-странице. А еще мы наделим наш Web-сайт графическим логотипом.

Предыдущая главаГлава 133 из 154Следующая глава