Реализация подгрузки содержимого

Давайте создадим новый Web-сайт, в котором и реализуем подгрузку содержимого. Его Web-страницы мы изготовим на основе соответствующих Web-страниц старого Web-сайта.

Прежде всего, создадим папку, которая станет корневой для нового Web-сайта. Назовем ее Site 2. Скопируем туда из корневой папки старого Web-сайта (Site 1) файлы main.css, main.js и ext-core.js. И сразу же создадим в ней папки chapters (для Web-страниц разделов), tags (для Web-страниц с описаниями тегов HTML), attrs (для Web-страниц, описывающих атрибуты стиля CSS) и samples (для Web-страниц с примерами).

Откроем в Блокноте Web-страницу index.htm старого Web-сайта и пересохраним под тем же именем в папке Site 2. Удалим из ее контейнера cmain все содержимое и сохраним.

Снова откроем Web-страницу index.htm старого Web-сайта и пересохраним ее в папке chapters, вложенной в папку Site 2, под именем html.htm. Удалим из нее все, кроме содержимого контейнера cmain, и сохраним снова.

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

Откроем Web-страницу index.htm уже нового Web-сайта и исправим интернет-адреса в гиперссылках, указывающих на другие Web-страницы. При этом будем иметь в виду, что интернет-адреса всех файлов с внедренными объектами (изображениями, аудио- и видеороликами) следует указывать относительно Web-страницы index.htm — ведь именно она фактически будет их загружать.

Web-страницы готовы. Настала пора создавать соответствующее поведение.

Откроем Web-страницу index.htm нового Web-сайта в Блокноте и удалим из секции ее заголовка код, объявляющий переменные outerIndex и innerText. Они нам больше не потребуются, так что незачем засорять память компьютера ненужными данными.

Потом откроем файл main.js нового Web-сайта, найдем в нем объявление функции selectItem и удалим его. Также удалим выражение, вызывающее эту функцию, из тела функции, которая передается методу onReady объекта Ext. Весь этот код нам больше не понадобится — скрытие и открытие вложенных списков и выделение пунктов полосы навигации мы реализуем по-другому, более "интеллектуально".

Прежде всего, мы будем хранить ссылки на выделенный в данный момент пункт полосы навигации и открытый вложенный список. Для этого мы объявим две переменные.

Далее мы напишем функцию, которая станет обработчиком события click пунктов полосы навигации. Эта функция будет выполнять три задачи. Во-первых, она реализует подгрузку содержимого из файла, чей интернет-адрес указан в гиперссылке пункта меню, на котором щелкнули мышью, и вывод его в контейнере cmain. Во-вторых, она будет делать тексты примеров скрывающимися и открывающимися при щелчке мышью на их первых потомках (для этого мы используем код, написанный ранее в главе 16). В-третьих, она будет управлять скрытием и открытием вложенных списков и выделением пунктов полосы навигации при щелчках на них.

1. Если посетитель щелкнул на пункте "внешнего" списка, формирующего полосу навигации, который имеет вложенный список, эта функция:

• удалит выделение с выделенного ранее пункта полосы навигации (если он был выделен). Выделенный пункт полосы навигации будет храниться в особой переменной, которую мы собираемся объявить;

• скроет открытый ранее вложенный список (если он был открыт и не вложен в пункт, на котором щелкнули мышью, — в этом случае нам нет нужды скрывать его, чтобы тотчас открыть). Открытый вложенный список также будет храниться в особой переменной, которую мы собираемся объявить;

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

2. Если посетитель щелкнул на пункте "внешнего" списка, не имеющего вложенного списка, эта функция:

• скроет открытый ранее вложенный список (если он был открыт);

• удалит выделение с выделенного ранее пункта полосы навигации (если он был выделен и если это не тот же самый пункт, на котором щелкнули мышью, — в этом случае незачем снимать с него выделение, чтобы сразу же выделить);

• выделит пункт, на котором щелкнули мышью.

3. Если посетитель щелкнул на пункте вложенного списка, эта функция:

• удалит выделение с выделенного ранее пункта полосы навигации (если он был выделен и если это не тот же самый пункт, на котором щелкнули мышью);

• выделит пункт, на котором щелкнули мышью.

Еще нам понадобятся две вспомогательные функции. Первая, совсем простая, будет вызвана после загрузки базовой Web-страницы index.htm и сделает все вложенные списки в полосе навигации скрытыми.

Вторая функция удалит все обработчики событий, привязанные к первым потомкам контейнеров со стилевым классом sample ("вместилища" для текста примеров). Перед тем как выводить в контейнере cmain новое содержимое, нужно удалить обработчики событий, привязанные к старому его содержимому. Так мы очистим память компьютера от не нужных более обработчиков событий и устраним потенциальную возможность появления ошибок. Данная функция будет вызываться в теле функции, которую мы описали чуть раньше, перед подгрузкой и выводом содержимого другого файла.

В самом начале файла main.js поместим два выражения:

var elLastInnerList = null;

var elLastItem = null;

Они объявляют переменные elLastInnerList и elLastItem и присваивают им значение null. Первая переменная будет хранить открытый в данный момент вложенный список, вторая — выделенный в данный момент пункт полосы навигации.

Далее объявим функцию loadFragment, которая будет обрабатывать событие click пунктов полосы навигации (листинг 17.1). Она будет принимать два параметра: пункт, на котором щелкнули мышью, в виде экземпляра объекта Element и экземпляр объекта EventObject, хранящий сведения о событии. Второй параметр необязательный.

Реализация подгрузки содержимого

Рассмотрим листинг 17.1 построчно.

Если функции loadFragment был передан второй параметр — экземпляр объекта EventObject, хранящий сведения о событии, — отменяем действие события по умолчанию и останавливаем его всплытие:

if (e)

--e.stopEvent();

Этот код перекочевал из функции-обработчика события click пунктов полосы навигации нашего предыдущего Web-сайта.

Получаем гиперссылку, вложенную в пункт полосы навигации, на котором щелкнули мышью:

var elA = elLI.child("A");

Если эта гиперссылка существует, выполняем следующий код:

if (elA) {

Вызываем функцию cleanupSamples, которая удалит обработчики событий у первых потомков контейнеров с текстами примеров:

cleanupSamples();

Мы объявим эту функцию потом.

Получаем интернет-адрес гиперссылки:

var href = elA.getAttribute("HREF");

Загружаем в контейнер cmain содержимое файла, на который указывает полученный интернет-адрес:

Ext.get("cmain").load({ url: href, success: prepareSamples });

После его загрузки вызываем функцию prepareSamples, которая добавит контейнерам с текстом примеров возможность скрытия и раскрытия в ответ на щелчки мышью.

Получаем список — родитель пункта полосы навигации, на котором щелкнули мышью, и проверяем, navbar ли его имя:

if (elLI.parent("UL").id == "navbar") {

Если это так, значит, данный пункт является пунктом "внешнего" списка navbar, в противном случае — вложенного.

Если это пункт "внешнего" списка, получаем вложенный в него список, если, конечно, он там присутствует:

var elInnerList = elLI.child("UL");

Проверяем, присутствует ли в пункте вложенный список:

if (elInnerList) {

Если вложенный список присутствует, проверяем, выделен ли в данный момент какой-либо пункт полосы навигации, т. е. содержит ли переменная elLastItem какое-либо значение, отличное от null:

if (elLastItem) {

elLastItem.removeClass("selected");

elLastItem = null;

}

Если это так, удаляем из привязки к выделенному пункту стилевой класс selected, делая его невыделенным, и присваиваем переменной elLastItem значение null, указывая тем самым, что ни один пункт полосы навигации в данный момент не выделен.

Также проверяем, открыт ли в данный момент какой-либо вложенный список (содержит ли переменная elLastInnerList какое-либо значение, отличное от null), и не тот ли это список, что вложен в пункт, на котором щелкнули мышью:

if ((elLastInnerList) && (elLastInnerList.dom !=

elInnerList.dom))

elLastInnerList.setDisplayed(false);

Если это так, скрываем этот список.

Обратим внимание, как мы проверяем тождественность открытого в данный момент вложенного списка тому, что содержится в пункте, на котором щелкнули мышью. Мы сравниваем не экземпляры объекта Element, возвращенные методами библиотеки Ext Core, а экземпляры объекта HTMLElement Web-обозревателя. Дело в том, что методы библиотеки Ext Core в разные моменты времени могут вернуть совершенно разные экземпляры объекта Element, тем не менее, представляющие один и тот же элемент Web-страницы. В то время как экземпляр объекта HTMLElement, представляющий данный элемент Web-страницы, всегда один и тот же.

Чтобы получить доступ к экземпляру объекта HTMLElement, мы используем свойство dom объекта Element.

Далее нам остается только открыть вложенный список, присутствующий в пункте, на котором щелкнули мышью:

elInnerList.setDisplayed(true);

...и сохранить его в переменной elLastInnerList:

elLastInnerList = elInnerList;

Если вложенный список в пункте "внешнего" списка, на котором щелкнули мышью, отсутствует, выполняется следующий код:

} else {

Проверяем, открыт ли в данный момент какой-либо вложенный список (содержит ли переменная elLastInnerList какое-либо значение, отличное от null):

if (elLastInnerList) {

elLastInnerList.setDisplayed(false);

elLastInnerList = null;

}

Если это так, скрываем открытый вложенный список и присваиваем переменной elLastInnerList значение null, указывая, что ни один вложенный список в данный момент не открыт.

Затем проверяем, выделен ли в данный момент какой-либо пункт полосы навигации (содержит ли переменная elLastItem какое-либо значение, отличное от null), и не тот ли это пункт, на котором щелкнули мышью:

if ((elLastItem) && (elLastItem.dom != elLI.dom))

elLastItem.removeClass("selected");

Здесь мы также сравниваем экземпляры объекта HTMLElement Web-обозревателя. Если какой-то пункт выделен и это не тот же самый пункт, на котором щелкнули мышью, снимаем с него выделение, убрав стилевой класс selected из привязки к нему.

Выделяем пункт, на котором щелкнули мышью, привязав к нему стилевой класс selected:

elLI.addClass("selected");

И сохраняем этот пункт в переменной elLastItem:

elLastItem = elLI;

}

Если пункт, на котором щелкнули мышью, находится во вложенном списке, выполняется следующий код:

} else {

Далее все нам уже знакомо:

if ((elLastItem) && (elLastItem.dom != elLI.dom))

elLastItem.removeClass("selected");

elLI.addClass("selected");

elLastItem = elLI;

}

}

Проверяем, выделен ли в данный момент какой-либо пункт полосы навигации, и не тот ли это пункт, на котором щелкнули мышью. Если это так, снимаем с него выделение, убрав стилевой класс selected из привязки к нему. Далее выделяем пункт, на котором щелкнули мышью, привязав к нему стилевой класс selected, и сохраняем этот пункт в переменной elLastItem. На этом выполнение функции loadFragment закончено.

Теперь объявим функцию hideInnerLists, которая скроет все вложенные списки в полосе навигации после загрузки базовой Web-страницы index.htm. Вот соответствующий код:

function hideInnerLists() {

var ceInnerLists = Ext.get("navbar").select("UL");

ceInnerLists.setDisplayed(false);

}

Мы получаем все списки, вложенные во "внешний" список navbar, и скрываем их.

На очереди — функция cleanupSamples (листинг 17.2). Она удалит обработчики событий, привязанные к первым потомкам контейнеров с текстом примеров (тех, к которым привязан стилевой класс sample).

Функция cleanupSamples

Получаем все элементы Web-страницы с привязанным стилевым классом sample, для каждого получаем первый потомок и убираем все привязанные к нему ранее обработчики событий.

Осталось только внести исправления в код тела функции, которая передается методу onReady объекта Ext. Прежде всего, найдем выражение, привязывающее обработчик события click к пунктам всех списков в полосе навигации. Исправим его так, чтобы оно выглядело следующим образом:

ceLinks.on("click", function(e, t){ loadFragment(Ext.get(this), e) });

Тело нового обработчика этого события представляет собой вызов объявленной нами ранее функции loadFragment. В качестве параметров мы передаем ей экземпляр объекта Element, представляющий пункт полосы навигации, на котором щелкнули мышью, и полученный из экземпляра объекта HTMLElement, доступный из переменной this, а также экземпляр объекта EventObject, хранящий сведения о событии и переданный функции-обработчику первым параметром.

А в конце тела функции, которая передается методу onReady объекта Ext, вставим два выражения:

hideInnerLists();

loadFragment(Ext.get("navbar").child("> LI:first"));

Первое вызывает функцию hideInnerLists, которую мы объявили ранее. Эта функция скроет все вложенные списки в полосе навигации после загрузки базовой Web-страницы index.htm.

Второе выражение вызовет функцию loadFragment и передаст ей в качестве параметра первый пункт "внешнего" списка navbar полосы навигации ("HTML"). В результате изначально в контейнер cmain будет загружено описание языка HTML (содержимое файла html.htm, хранящегося в папке chapters).

Сохраним файл main.js. И проверим наш второй Web-сайт в действии. Как мы помним, для этого понадобится Web-сервер, который у нас уже есть — Microsoft Internet Information Services.

Сохраним файл main.js. И проверим наш второй Web-сайт в действии.