Первую задачу — соотношение пункта полосы навигации со списком связанных материалов — мы решили.
Найдем объявление функции prepareSamples, которая подготавливает текст примеров и, что важно для нас, выполняется после загрузки фрагмента содержимого. Добавим в конец тела функции, передаваемой в качестве параметра методу each, такое выражение:
generateRelated();
Это вызов функции generateRelated, которая и создаст раздел "См. также" и которую мы сейчас объявим.
Не будем откладывать дело в долгий ящик. Листинг 19.2 содержит объявление функции generateRelated.
Листинг 19.2
function generateRelated() {
var s = "";
var oRelated = elLastItem.dom.related;
if (oRelated) {
for (var i = 0; i < oRelated.length; i++) {
if (s!= "")
s += ", ";
s += "<CODE><A HREF="" + oRelated[i].url + "">" +
oRelated[i].name + "</A></CODE>";
}
var htelRelated = Ext.get("cmain"). insertHtml("beforeEnd", "<P>См. также: " + s + "</P>"); Ext.fly(htelRelated). 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);
});
}
Рассмотрим приведенный код построчно.
Объявляем переменную s, в которой будет храниться HTML-код, формирующий раздел "См. также" в виде строки:
var s = "";
Первое, что нам нужно, — получить список материалов, связанных с загруженной в данный момент Web-страницей (точнее, фрагментом содержимого). Как его получить? Вспомним, что еще в главе 17 мы объявили переменную elLastItem. Она хранит пункт полосы навигации, на котором посетитель щелкнул мышью и который как раз и соответствует загруженному в данный момент фрагменту содержимого. Вот и решение:
var oRelated = elLastItem.dom.related;
Значение переменной elLastItem — это экземпляр объекта Element. Соответствующий ему экземпляр объекта HTMLElement мы можем получить через свойство dom. А полученный экземпляр объекта HTMLElement, в свою очередь, содержит свойство related, которое и хранит массив конфигураторов, представляющих Web-страницы со связанными материалами; мы сами создали это свойство при формировании пунктов вложенных списков (исправленная функция generateInnerList).
Проверяем, присутствует ли это свойство в экземпляре объекта HTMLElement, т. е. существует ли у данной Web-страницы список связанных материалов:
if (oRelated) {
Если существует, запускаем цикл со счетчиком, который обработает все элементы этого массива:
for (var i = 0; i < oRelated.length; i++) {
Фрагменты HTML-кода, формирующие отдельные гиперссылки раздела "См.
также", мы будем добавлять в строку, хранящуюся в переменной s:
if (s!= "")
s += ", ";
Эти гиперссылки следует разделить запятыми, что и выполняет приведенное выражение. Оно проверяет, есть ли в переменной s непустая строка, т. е. сформирована ли в ней хотя бы одна гиперссылка, и, если это так, добавляет к ней запятую — разделитель гиперссылок.
Формируем HTML-код, создающий гиперссылку на очередную Web-страницу из списка связанных материалов, и добавляем его к значению переменной s:
s += "<CODE><A HREF="" + oRelated[i].url + "">" + oRelated[i].name + "</A></CODE>";
}
На этом тело цикла завершается.
Далее создаем на основе сформированного HTML-кода абзац, который и станет разделом "См. также". Добавляем его в самый конец контейнера cmain (перед его закрывающим тегом):
var htelRelated = Ext.get("cmain"). insertHtml("beforeEnd", "<P>См. также: " + s + "</P>");
Выбираем из сформированного в предыдущем выражении абзаца все гиперссылки и привязываем к ним функцию — обработчик события click, которую там же и объявляем:
Ext.fly(htelRelated). select("A"). on("click", function(e, t) {
Первым делом эта функция получит значение атрибута HREF — интернет-адрес — гиперссылки, на которой щелкнули мышью:
var href = Ext.fly(this). getAttribute("href");
Далее она ищет в списке navbar гиперссылку с тем же интернет-адресом:
var elA = Ext.get("navbar"). child("A[href=" + href + "]");
Пункты нашей полосы навигации не содержат повторяющихся интернет-адресов, поэтому такой прием будет работать.
Найдя такую гиперссылку, она получает ее родителя — сам пункт:
var elItem = elA.parent("LI");
который, вместе с экземпляром объекта EventObject, представляющим возникшее событие, "скармливает" объявленной нами в главе 17 функции loadFragment. Последняя выполнит загрузку соответствующего фрагмента содержимого и выделит соответствующий пункт полосы навигации:
loadFragment(elItem, e);
});
}
На этом выполнение функции generateRelated заканчивается.
Теперь отыщем код, объявляющий функцию cleanupSamples. Она, как мы помним, удаляет обработчики событий у текста примеров перед загрузкой другого фрагмента содержимого. Это нужно, чтобы не засорять внутренние структуры данных библиотеки Ext Core сведениями о привязке обработчиков событий к уже не существующим элементам Web-страницы.
Нам нужно дополнить этот код, чтобы он также удалял обработчики событий у гиперссылок раздела "См. также". Сделаем проще — будем выбирать все гиперссылки в контейнере cmain и удалять у них обработчики событий.
Листинг 19.3 содержит дополненное объявление функции cleanupSamples.
Листинг 19.3
function cleanupSamples() {
var ceSamples = Ext.select(".sample");
ceSamples.each(function(el, cl, ind){ var elH6 = el.child(":first"); elH6.removeAllListeners();
});
var ceA = Ext.get("cmain"). select("A");
ceA.removeAllListeners();
}
Так, вторая и третья задачи решены. Мы сформировали раздел "См. также" и реализовали загрузку Web-страницы при щелчке на гиперссылке этого раздела.
Теперь представим себе такую ситуацию. Посетитель щелкает на каком-либо пункте полосы навигации, Web-обозреватель выводит соответствующую Web-страницу и формирует на ней раздел "См. также". Этот раздел содержит несколько гиперссылок, указывающих на Web-страницы с описаниями тегов HTML (первый раздел — "HTML"), и несколько гиперссылок, указывающих на Web-страницы с описаниями атрибутов стиля CSS (второй раздел — "CSS"). Предположим, что загруженная в данный момент Web-страница также содержит описание тега HTML (принадлежит к первому разделу); значит, первый, представляющий Web-страницы из первого раздела, вложенный список в полосе навигации открыт, остальные — скрыты.
В этот момент посетитель щелкает на гиперссылке раздела "См. также", ведущей на Web-страницу с описанием атрибута стиля CSS (принадлежащей второму разделу), и Web-страница успешно загружается. По идее, второй вложенный список (который представляет все Web-страницы второго раздела) в полосе навигации должен быть открыт, а первый, открытый ранее, — скрыт. Ничего подобного! Первый вложенный список так и останется открытым.
Дело в том, что, создавая в главе 17 Web-сценарий, управляющий скрытием и раскрытием вложенных списков в полосе навигации и выделением ее пунктов, мы полагали, что щелкать на пунктах полосы навигации будет человек. А он в принципе не может щелкнуть на пункте, находящемся в скрытом списке, — ведь скрытый список вообще не присутствует на Web-странице. Поэтому мы не реализовали в функции loadFragment возможность открытия вложенного списка, на пункте которого щелкнул посетитель, — это было просто незачем.
Сейчас же мы написали функцию generateRelated, которая создает раздел "См. также" с набором гиперссылок и привязывает к ним обработчик события click. Этот обработчик находит в полосе навигации пункт, который имеет гиперссылку с тем же интернет-адресом, и, если можно так сказать, программно "щелкает" на нем. А он ведь может "щелкнуть" и на пункте скрытого списка!
Вывод: нам потребуется дополнить объявление функции loadFragment так, чтобы она открывала вложенный список, на пункте которого "щелкнули", если, конечно, он еще не открыт. Найдем это объявление и отыщем в нем фрагмент кода, приведенный в листинге 19.4.
Листинг 19.4
.
} else {
if ((elLastItem) && (elLastItem.dom!= elLI.dom))
elLastItem.removeClass("selected");
elLI.addClass("selected");
elLastItem = elLI;
}
Этот код управляет выделением пункта вложенного списка, на котором щелкнули мышью или "щелкнули" программно. Дополним его так, как показано в листинге 19.5.
Листинг 19.5
} else {
var elInnerList = elLI.parent("UL");
if ((elLastInnerList) && (elLastInnerList.dom!= elInnerList.dom))
elLastInnerList.setDisplayed(false); elInnerList.setDisplayed(true); elLastInnerList = elInnerList;
if ((elLastItem) && (elLastItem.dom!= elLI.dom))
elLastItem.removeClass("selected");
elLI.addClass("selected");
elLastItem = elLI;
}
Добавленные нами выражения находят вложенный список, в котором присутствует данный пункт, проверяют, открыт ли он в текущий момент, и, если не открыт, открывают, скрывая при этом ранее открытый список.
Вот решена и четвертая задача… Уф-ф-ф!
Сохраним все исправленные файлы и проверим готовую Web-страницу index.htm в действии. Откроем Web-обозреватель, наберем в поле ввода интернет-адрес http://localhost, пощелкаем на пунктах полосы навигации и гиперссылках раздела "См. также" и посмотрим на сменяющие друг друга Web-страницы и скрывающиеся и открывающиеся вложенные списки. Красота!