- •Лабораторная работа № 16 «JavaScript: Web-формы и элементы управления. Свободно позиционируемые элементы Web-страницы
- •Создание Web-форм
- •Создание элементов управления
- •Поле ввода
- •Поле ввода пароля
- •Поле ввода значения для поиска
- •Область редактирования
- •Переключатель
- •Список, обычный или раскрывающийся
- •Надпись
- •Прочие элементы управления
- •Специальные селекторы css, предназначенные для работы с элементами управления
- •Свойства и методы объекта htmlElement, применяемые для работы с элементами управления
- •Свойства и методы объекта Element, применяемые для работы с элементами управления
- •События элементов управления
- •Реализация поиска на Web-сайте
- •Подготовка базы данных
- •Создание Web-формы
- •Написание Web-сценария, выполняющего поиск
- •Понятие свободно позиционируемого элемента Web-страницы
- •Создание свободно позиционируемых элементов
- •Средства библиотеки Ext Core для управления свободно позиционируемыми элементами
- •Реализация усовершенствованного поиска
- •Создание контейнера с Web-формой поиска
Подготовка базы данных
Задание 1. Укажем для каждого элемента массива, составляющего базу данных и представляющего одну из Web-страниц, список ключевых слов.
Для этого создадим у конфигураторов — элементов этих массивов новое свойство keyword, которому и присвоим список соответствующих ключевых слов. Он будет представлять собой обычную строку с ключевыми словами, разделенными запятыми, — так его проще обрабатывать.
Откройте файл Web-сценариев data.js и поместите после кода, создающего свойство related со связанными данными, но перед кодом, выполняющим сортировку базы, такое выражение:
aHTML[0].keyword = "тип,версия";
Здесь мы взяли первый элемент массива aHTML (с индексом 0), добавили к хранящемуся в нем конфигуратору свойство keyword и присвоили этому свойству строку с ключевыми словами "тип" и "версия". Следовательно, мы указали, что Web-страницу с описанием тега <!DOCTYPE> будут характеризовать эти два ключевых слова.
Аналогично укажите ключевые слова для остальных Web-страниц нашего Web-сайта.
Создание Web-формы
Задание 2. Создадим Web-форму, в которую посетитель будет вводить искомое слово или его часть.
Вставим форму в контейнер cnavbar, ниже полосы навигации, непосредственно перед закрывающим тегом </DIV>, формирующим этот контейнер. Позже мы найдем Web-форме поиска местоположение получше.
Наша первая "рабочая" Web-форма будет содержать следующие элементы:
надпись "Поиск", чтобы посетитель сразу понял, зачем нужна эта Web-форма;
поле ввода значения для поиска, где указывается искомое слово или начало слова;
кнопку, запускающую поиск;
раскрывающийся список для выбора режима поиска (только по названиям, только по ключевым словам или одновременно по названиям и по ключевым словам).
Содержимое Web-формы мы поместим в один абзац, который разобьем на три строки с помощью тегов разрыва строк. Первая строка будет содержать надпись, вторая — поле ввода и кнопку, третья — раскрывающийся список.
Можно, конечно, разместить эти элементы в трех отдельных абзацах, но так Web-форма займет на Web-странице слишком много места.
Поле ввода искомого слова мы назовем keyword, кнопку — find, а раскрывающийся список — search_in.
Листинг 16.19 содержит HTML-код, создающий Web-форму.
Листинг 16.19
Вставьте его в соответствующее место файла фрагмента html.htm.
Обязательно проверьте, правильно ли наша Web-форма отображается на Web-странице. Если вы допустили в HTML-коде ошибку, лучше исправить ее сейчас.
Написание Web-сценария, выполняющего поиск
Задание 3. Напишем Web-сценарий, который будет искать Web-страницы, удовлетворяющие заданным посетителем условиям.
Откройте файл Web-сценария main.js и поместите где-либо в теле функции, передаваемой в качестве параметра методу onReady объекта Ext, такое выражение:
Ext.get("find").on("click", searchData);
Оно привязывает к событию click кнопки find функцию-обработчик searchData, которая будет выполнять поиск и выводить его результаты и которую мы объявим чуть позже. Кнопка find созданной нами Web-формы запускает процесс поиска, а событие click, как мы уже знаем, возникает при щелчке на кнопке.
Теперь объявите функцию searchData. Она не будет ни принимать параметры, ни возвращать результат. Объявляющий ее код (листинг 16.20) поместите где-либо перед вызовом метода onReady объекта Ext.
Листинг 16.20
Рассмотрим его построчно.
Получаем искомое слово, введенное посетителем в поле ввода keyword:
var sKeyword = Ext.get("keyword").getValue(false);
Проверяем, ввел ли посетитель вообще что-либо в это поле ввода:
if (sKeyword != "") {
Если ввел, получаем номер пункта, выбранного в раскрывающемся списке search_in:
var iSearchMode = Ext.getDom("search_in").selectedIndex;
Объявляем массив, который будет хранить набор элементов массивов aHTML, aCSS и aSamples, имеющих название или одно из ключевых слов, начало которого совпадает с введенным посетителем словом:
var aResult = [];
Фактически этот массив будет хранить результаты поиска.
Для каждого из массивов aHTML, aCSS и aSamples вызываем функцию searchInArray, которую объявим потом:
searchInArray(sKeyword, aHTML, aResult, iSearchMode);
searchInArray(sKeyword, aCSS, aResult, iSearchMode);
searchInArray(sKeyword, aSamples, aResult, iSearchMode);
Эта функция будет искать элементы в массиве, переданном ей вторым параметром, имеющие название или одно из ключевых слов, начало которого совпадает со словом, переданным первым параметром, и помещать их в массив с результатами поиска, переданный третьим параметром. Четвертым параметром этой функции передается номер пункта, выбранного в раскрывающемся списке search_in, — режим поиска.
Проверяем, есть ли в массиве с результатами поиска хоть один элемент, т. е. увенчался ли поиск успехом:
if (aResult.length > 0) {
Если так, объявляем переменную, которая будет хранить строку с HTML-кодом, формирующим пункты списка с результатами поиска:
var s = "";
Ранее мы договорились, что будем выводить результаты поиска на Web-страницу в виде списка HTML; каждый пункт этого списка будет содержать гиперссылку на соответствующую Web-страницу.
Запускаем цикл со счетчиком, который будет просматривать все элементы массива с результатами поиска:
for (var i = 0; i < aResult.length; i++) {
Тело этого цикла на основе каждого элемента массива с результатами поиска сформирует HTML-код, создающий пункт списка с гиперссылкой:
s += "<LI><A HREF=\"" + aResult[i].url + "\">" +
aResult[i].name + "</A></LI>";
}
На основе полученного таким образом HTML-кода создаем список с результатами поиска и помещаем его в самом конце контейнера cmain:
var htelResult = Ext.get("cmain").insertHtml("beforeEnd",
"<P>Результаты поиска:</P><UL>" + s + "</UL>");
Выбираем из этого списка все гиперссылки и привязываем к ним обработчик собы-тия click, который будет обрабатывать щелчки на этих гиперссылках и выполнять
загрузку соответствующей Web-страницы:
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);
});
}
}
Этот фрагмент кода без изменений перекочевал сюда из функции generateRelated,
объявленной в главе 19. (В принципе, будет лучше оформить его в виде отдельной
функции, но это вы можете сделать сами, в качестве домашнего задания.)
На этом выполнение функции searchData заканчивается.
Осталось объявить функцию searchInArray, которая, собственно, будет выполнять
поиск в массивах, составляющих базу данных. Объявляющий код (листинг 16.21)
мы поместим где-либо перед объявлением функции searchData.
Листинг 16.21
Как уже говорилось, эта функция принимает четыре параметра:
искомое слово в виде строки;
массив, составляющий базу данных, в котором будет выполняться поиск;
массив, в который будут помещаться результаты поиска;
число, обозначающее режим поиска. Фактически это номер пункта, выбранного
посетителем в раскрывающемся списке search_in.
Результат эта функция возвращать не будет.
Давайте рассмотрим объявляющий ее код построчно, т. к. он довольно сложен, хоть
и невелик по размеру.
Объявляем служебные переменные:
var sN, sK;
Преобразуем полученное первым параметром искомое слово к нижнему регистру,
добавляем к ней спереди запятую и сохраняем в служебной переменной для даль-нейшего использования:
var sKw = "," + sKeyword.toLowerCase();
Посетитель — человек непредсказуемый. Кто знает, в каком регистре он наберет
искомое слово — в верхнем или нижнем, прописными буквами или строчными.
А названия Web-страниц нашего Web-сайта указаны как в верхнем, так и в нижнем
регистре. И строка, набранная в верхнем регистре, не равна строке, содержащей те
же символы, но набранные в нижнем регистре; так, строки "title" и "TITLE", хоть и
содержат одни и те же символы, не равны, поскольку эти символы набраны в раз-ных регистрах.
Выход — перед сравнением строк принудительно преобразовать их к какому-либо
одному регистру, скажем, к нижнему. В этом нам поможет метод toLowerCase объ-екта JavaScript String. Он как раз возвращает строку, равную той, для которой он
вызван, но набранную в нижнем регистре. Параметров он не принимает.
Но зачем добавлять к искомой строке спереди запятую? Давайте разберемся.
Предположим, посетитель захотел найти материалы по тегу <IMG>. Причем посети-тель попался на редкость ленивый, и, вместо того чтобы набрать имя тега пол-ностью, ввел только букву "I".
Средства JavaScript позволяют узнать, присутствует ли в какой-либо строке указан-ная подстрока. (Как мы потом узнаем, за это "отвечает" особый метод объекта
String.) Другими словами, приняв за подстроку введенное посетителем искомое
слово, мы с помощью этих средств можем легко узнать, присутствует ли оно в на-звании или списке ключевых слов какого-либо элемента базы данных. Так, мы вы-ясним, что в строке "IMG" присутствует подстрока "I", а в строке "!DOCTYPE" —
нет.
Но ведь подстрока "I" присутствует и в строках "AUDIO", "VIDEO" и "TITLE"!
А мы решили, что будем выбирать только те материалы, начало названий или клю-чевых слов содержит указанное слово. Начало, а не середина или конец! К сожале-нию, средства JavaScript не позволяют указать, в какой именно части слова должна
присутствовать искомая подстрока...
Чтобы решить возникшую проблему, мы пойдем на небольшую хитрость. Мы до-бавим в начало искомого слова, названия и списка ключевых слов каждой Web-страницы какой-нибудь символ, например, запятую. А уже после этого будем вы-полнять сам поиск.
Например, если мы добавим к строкам "I", "IMG" и "AUDIO" спереди запятую, то
получим ",I", ",IMG" и ",AUDIO". Посмотрим, что получится: строка ",IMG" со-держит подстроку ",I", а ",AUDIO" — не содержит. Принятое нами правило поис-ка — указанное слово должно содержаться в начале названия — теперь выполняет-ся. Как говорится, не мытьем, так катаньем. Ладно, поехали дальше...
Запускаем цикл со счетчиком, который будет просматривать все элементы массива
базы данных, переданного вторым параметром:
for(var i = 0; i < aDataArray.length; i++) {
В теле этого цикла мы получаем название очередного элемента этого массива, пре-образуем его к нижнему регистру, добавляем к нему спереди запятую и присваива-ем объявленной ранее служебной переменной:
sN = "," + aDataArray[i].name.toLowerCase();
Проверяем, есть ли у данного элемента свойство keyword:
if (aDataArray[i].keyword)
sK = "," + aDataArray[i].keyword.toLowerCase()
else
sK = "";
(Ранее мы решили, что оно будет необязательным.) Если оно есть, преобразуем его
значение — список ключевых слов — к нижнему регистру, добавляем к нему спе-реди запятую и присваиваем объявленной ранее служебной переменной. Если его
нет, присваиваем той же служебной переменной пустую строку — "пустой" список
ключевых слов.
Если посетитель выбрал первый или третий пункты раскрывающегося списка
search_in (т. е. если указан режим поиска по названиям или по названиям и ключе-вым словам; номер выбранного пункта списка search_in передается четвертым па-раметром) и если в названии элемента массива присутствует указанное посетите-лем слово:
if (((iSearchMode == 0) || (iSearchMode == 2)) &&
(sN.indexOf(sKw) != -1))
мы присваиваем этот элемент новому элементу массива результатов, переданного
третьим параметром:
aResultArray[aResultArray.length] = aDataArray[i]
Чтобы добавить к массиву новый элемент, нужно дать ему индекс, на единицу
больший индекса его последнего уже существующего элемента. В качестве этого
индекса удобно использовать размер массива — ведь он всегда на единицу больше
индекса последнего элемента массива (конечно, при условии, что индексы всех
элементов данного массива представляют собой непрерывающуюся последо-вательность чисел, причем каждое следующее число больше предыдущего на еди-ницу).
Если посетитель выбрал второй или третий пункты раскрывающегося списка
search_in (т. е. если указан режим поиска по ключевым словам или по названиям и
ключевым словам) и если в списке ключевых слов элемента массива присутствует
указанное посетителем слово
else
if (((iSearchMode == 1) || (iSearchMode == 2)) &&
(sK.indexOf(sKw) != -1))
мы присваиваем этот элемент новому элементу массива результатов, переданного
третьим параметром:
aResultArray[aResultArray.length] = aDataArray[i];
}
На этом выполнение тела цикла и тела функции searchInArray заканчивается.
Что ж, поиск готов. Откроем наш Web-сайт, наберем в поле ввода какое-либо слово
и нажмем кнопку Искать!. Если поиск увенчается успехом, в самом конце контей-
нера cmain мы увидим список, пункты которого будут содержать гиперссылки на
найденные Web-страницы.
Б. СВОБОДНО ПОЗИЦИОНИРУЕМЫЕ ЭЛЕМЕНТЫ WEB-СТРАНИЦЫ
В предыдущей главе мы познакомились с Web-формами и элементами управления,
HTML-тегами для их создания и средствами объектов Web-обозревателя и библио-теки Ext Core для работы с ними. На основе этих элементов управления и базы дан-ных мы создали систему поиска для своего Web-сайта. Наш небольшой Web-сайтик
теперь выглядит просто шикарно!
Только вот поиск у нас вышел какой-то корявый, больше похожий не на готовое
решение, а на экспериментальный "прибамбас", который со временем переделают
во что-либо более приемлемое (или уберут совсем). Давайте сами посмотрим на
него критическим взглядом.
Контейнер с полосой навигации — не лучшее место для Web-формы поиска. То,
что она нарушает дизайн Web-страницы, не страшно — задать для нее подходя-щее представление не составит для нас труда. Хуже другое — полоса навигации
в какой-то момент станет слишком большой, не поместится в контейнер, Web-форма "уедет" вниз, и посетителю, чтобы до нее добраться, придется пользо-ваться полосами прокрутки. А ведь он должен догадаться, что Web-форма поис-ка еще присутствует на Web-странице, а не пропала бесследно и невесть куда!
Низ контейнера с основным содержимым тоже плохо подходит для размещения
результатов поиска: основное содержимое может оказаться слишком большим,
чтобы поместиться в контейнер полностью, и посетителю придется пользоваться
полосами прокрутки, чтобы добраться до результатов поиска.
Теперь предположим, что посетитель выполнил поиск, который оказался удач-ным, и в низу контейнера с основным содержимым появится список с результа-тами. После этого посетитель снова выполнил успешный поиск, и в низу кон-тейнера с основным содержимым появится еще один список — с результатами
нового поиска. Если повторять поиск снова и снова, будут появляться все новые
списки с результатами, и так без конца.
В принципе, некоторые из перечисленных проблем можно решить известными нам
средствами. Как уже говорилось, для Web-формы мы можем создать представле-ние, "облагораживающее" ее. Мы способны выявлять, присутствует ли уже в ос-новном содержимом список с результатами поиска, и удалять его; для этого мы
можем привязать к списку стилевой класс или дать ему имя, по которому сможем
его найти.
Но куда выводить результаты поиска, чтобы посетитель сразу их увидел?
Напрашивается вывод: создать на Web-странице еще один блочный контейнер, по-местить в него Web-форму и туда же выводить результаты поиска. Но дополни-тельный контейнер займет определенное место на Web-странице, может быть,
слишком много места. А значит, останется меньше пространства для остальных
контейнеров.
Мы можем сделать этот контейнер изначально небольшим, ровно таким, чтобы
вместить только Web-форму. Если же поиск увенчается успехом, мы увеличим
размер контейнера, чтобы он вместил список с результатами. Но тогда остальные
контейнеры будут "ездить" по Web-странице туда-сюда, чем немало развеселят по-сетителей. Хорошее настроение — оно, конечно, замечательно, но все равно это не
выход.
