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-сайт графическим логотипом.
ГЛАВА 22. Программируемая графика
В предыдущей главе мы познакомились со свободно позиционируемыми элементами Web-страницы и использовали их, чтобы улучшить систему поиска на нашем Web-сайте. Получилось неплохо, правда?
На этом мы закончим с поиском и обратим внимание на заголовок нашего Web-сайта. Как-то неказисто он выглядит — обычный текст без всяких изысков. И это в то время, когда большинство Web-сайтов щеголяют шикарными графическими логотипами. Почему у нас такого нет?
Потому что мы этим еще не занимались. Вообще, сделать графический логотип Web-сайта проще простого — достаточно нарисовать его в каком-либо графическом редакторе и сохранить в любом формате, применяемом в Интернете. А как поместить на Web-страницу графическое изображение, мы уже знаем — изучали еще в главе 4.
Существует и другой путь — задействовать возможности программируемой графики, предлагаемые HTML 5. Они позволяют нарисовать любую, даже весьма сложную фигуру программно, из Web-сценария. Причем пользоваться этими возможностями не так и сложно — достаточно уяснить пару концепций и выучить несколько десятков методов.
Давайте так и сделаем. Ведь если мы взялись изучать HTML 5, так уж будем идти до конца.
Канва
Начнем сразу с первой концепции, на основе которой работает программируемая графика HTML 5 и которую нам нужно уяснить. Все рисование выполняется в особом элементе Web-страницы, еще нам не встречавшемся, — в канве (ее еще называют холстом). В других элементах (абзацах, заголовках, таблицах, графических изображениях и пр.) программное рисование не работает.
Канву создают с помощью парного тега <CANVAS>:
<CANVAS ID="<имя>" [WIDTH="<ширина>"] [HEIGHT="<высота>"]></CANVAS>
Мы уже знаем, что рисование в канве выполняется программно, в Web-сценарии. А перед тем как что-то нарисовать, нам придется получить доступ к канве. Сделать это проще всего через имя, заданное атрибутом тега ID. Именно поэтому данный атрибут тега помечен здесь как обязательный.
Необязательные атрибуты тега WIDTH и HEIGHT задают, соответственно, ширину и высоту канвы в пикселах (по умолчанию 300 150 пикселов).
ВНИМАНИЕ!
Задавать размеры канвы с помощью стилей CSS не рекомендуется.
Вот HTML-код, создающий на странице канву cnv размером 400 300 пикселов:
<CANVAS ID="cnv" WIDTH="400" HEIGHT="300"></CANVAS>
Канва представляется как экземпляр объекта Web-обозревателя HTMLCanvasElement, производный от объекта HTMLElement. Для нас будет полезен только единственный метод этого объекта, который мы скоро рассмотрим.
Контекст рисования
Рисование на канве выполняется с помощью особых свойств и методов объекта… нет, не HTMLCanvasElement, а CanvasRenderingContext2D. Этот объект представляет так называемый контекст рисования, который можно рассматривать как набор инструментов, используемый для рисования на данной канве.